brcm2708: add kernel 4.14 support
[openwrt/staging/chunkeey.git] / target / linux / brcm2708 / patches-4.14 / 950-0083-ASoC-Add-driver-for-Cirrus-Logic-Audio-Card.patch
1 From 7c7641a4796fa9740ed038f96484f1088587b22d 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 083/454] 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 sound/soc/bcm/Kconfig | 9 +
14 sound/soc/bcm/Makefile | 2 +
15 sound/soc/bcm/rpi-cirrus.c | 1003 ++++++++++++++++++++++++++++++++++++
16 3 files changed, 1014 insertions(+)
17 create mode 100644 sound/soc/bcm/rpi-cirrus.c
18
19 --- a/sound/soc/bcm/Kconfig
20 +++ b/sound/soc/bcm/Kconfig
21 @@ -46,6 +46,15 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP
22 help
23 Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
24
25 +config SND_BCM2708_SOC_RPI_CIRRUS
26 + tristate "Support for Cirrus Logic Audio Card"
27 + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
28 + select SND_SOC_WM5102
29 + select SND_SOC_WM8804
30 + help
31 + Say Y or M if you want to add support for the Wolfson and
32 + Cirrus Logic audio cards.
33 +
34 config SND_BCM2708_SOC_RPI_DAC
35 tristate "Support for RPi-DAC"
36 depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
37 --- a/sound/soc/bcm/Makefile
38 +++ b/sound/soc/bcm/Makefile
39 @@ -16,6 +16,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
40 snd-soc-hifiberry-digi-objs := hifiberry_digi.o
41 snd-soc-justboom-dac-objs := justboom-dac.o
42 snd-soc-justboom-digi-objs := justboom-digi.o
43 +snd-soc-rpi-cirrus-objs := rpi-cirrus.o
44 snd-soc-rpi-dac-objs := rpi-dac.o
45 snd-soc-rpi-proto-objs := rpi-proto.o
46 snd-soc-iqaudio-dac-objs := iqaudio-dac.o
47 @@ -36,6 +37,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
48 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
49 obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
50 obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI) += snd-soc-justboom-digi.o
51 +obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
52 obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
53 obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
54 obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
55 --- /dev/null
56 +++ b/sound/soc/bcm/rpi-cirrus.c
57 @@ -0,0 +1,1003 @@
58 +/*
59 + * ASoC machine driver for Cirrus Logic Audio Card
60 + * (with WM5102 and WM8804 codecs)
61 + *
62 + * Copyright 2015-2017 Matthias Reichl <hias@horus.com>
63 + *
64 + * Based on rpi-cirrus-sound-pi driver (c) Wolfson / Cirrus Logic Inc.
65 + *
66 + * This program is free software; you can redistribute it and/or modify
67 + * it under the terms of the GNU General Public License version 2 as
68 + * published by the Free Software Foundation.
69 + */
70 +
71 +#include <linux/module.h>
72 +#include <linux/mutex.h>
73 +#include <linux/slab.h>
74 +#include <linux/list.h>
75 +#include <linux/delay.h>
76 +#include <sound/pcm_params.h>
77 +
78 +#include <linux/mfd/arizona/registers.h>
79 +
80 +#include "../codecs/wm5102.h"
81 +#include "../codecs/wm8804.h"
82 +
83 +#define WM8804_CLKOUT_HZ 12000000
84 +
85 +#define RPI_CIRRUS_DEFAULT_RATE 44100
86 +#define WM5102_MAX_SYSCLK_1 49152000 /* max sysclk for 4K family */
87 +#define WM5102_MAX_SYSCLK_2 45158400 /* max sysclk for 11.025K family */
88 +
89 +static inline unsigned int calc_sysclk(unsigned int rate)
90 +{
91 + return (rate % 4000) ? WM5102_MAX_SYSCLK_2 : WM5102_MAX_SYSCLK_1;
92 +}
93 +
94 +enum {
95 + DAI_WM5102 = 0,
96 + DAI_WM8804,
97 +};
98 +
99 +struct rpi_cirrus_priv {
100 + /* mutex for synchronzing FLL1 access with DAPM */
101 + struct mutex lock;
102 + unsigned int card_rate;
103 + int sync_path_enable;
104 + int fll1_freq; /* negative means RefClock in spdif rx case */
105 +
106 + /* track hw params/free for substreams */
107 + unsigned int params_set;
108 + unsigned int min_rate_idx, max_rate_idx;
109 + unsigned char iec958_status[4];
110 +};
111 +
112 +/* helper functions */
113 +static inline struct snd_soc_pcm_runtime *get_wm5102_runtime(
114 + struct snd_soc_card *card) {
115 + return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name);
116 +}
117 +
118 +static inline struct snd_soc_pcm_runtime *get_wm8804_runtime(
119 + struct snd_soc_card *card) {
120 + return snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name);
121 +}
122 +
123 +
124 +struct rate_info {
125 + unsigned int value;
126 + char *text;
127 +};
128 +
129 +static struct rate_info min_rates[] = {
130 + { 0, "off"},
131 + { 32000, "32kHz"},
132 + { 44100, "44.1kHz"}
133 +};
134 +
135 +#define NUM_MIN_RATES ARRAY_SIZE(min_rates)
136 +
137 +static int rpi_cirrus_min_rate_info(struct snd_kcontrol *kcontrol,
138 + struct snd_ctl_elem_info *uinfo)
139 +{
140 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
141 + uinfo->count = 1;
142 + uinfo->value.enumerated.items = NUM_MIN_RATES;
143 +
144 + if (uinfo->value.enumerated.item >= NUM_MIN_RATES)
145 + uinfo->value.enumerated.item = NUM_MIN_RATES - 1;
146 + strcpy(uinfo->value.enumerated.name,
147 + min_rates[uinfo->value.enumerated.item].text);
148 + return 0;
149 +}
150 +
151 +static int rpi_cirrus_min_rate_get(struct snd_kcontrol *kcontrol,
152 + struct snd_ctl_elem_value *ucontrol)
153 +{
154 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
155 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
156 +
157 + ucontrol->value.enumerated.item[0] = priv->min_rate_idx;
158 + return 0;
159 +}
160 +
161 +static int rpi_cirrus_min_rate_put(struct snd_kcontrol *kcontrol,
162 + struct snd_ctl_elem_value *ucontrol)
163 +{
164 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
165 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
166 + int changed = 0;
167 +
168 + if (priv->min_rate_idx != ucontrol->value.enumerated.item[0]) {
169 + changed = 1;
170 + priv->min_rate_idx = ucontrol->value.enumerated.item[0];
171 + }
172 +
173 + return changed;
174 +}
175 +
176 +static struct rate_info max_rates[] = {
177 + { 0, "off"},
178 + { 48000, "48kHz"},
179 + { 96000, "96kHz"}
180 +};
181 +
182 +#define NUM_MAX_RATES ARRAY_SIZE(max_rates)
183 +
184 +static int rpi_cirrus_max_rate_info(struct snd_kcontrol *kcontrol,
185 + struct snd_ctl_elem_info *uinfo)
186 +{
187 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
188 + uinfo->count = 1;
189 + uinfo->value.enumerated.items = NUM_MAX_RATES;
190 + if (uinfo->value.enumerated.item >= NUM_MAX_RATES)
191 + uinfo->value.enumerated.item = NUM_MAX_RATES - 1;
192 + strcpy(uinfo->value.enumerated.name,
193 + max_rates[uinfo->value.enumerated.item].text);
194 + return 0;
195 +}
196 +
197 +static int rpi_cirrus_max_rate_get(struct snd_kcontrol *kcontrol,
198 + struct snd_ctl_elem_value *ucontrol)
199 +{
200 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
201 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
202 +
203 + ucontrol->value.enumerated.item[0] = priv->max_rate_idx;
204 + return 0;
205 +}
206 +
207 +static int rpi_cirrus_max_rate_put(struct snd_kcontrol *kcontrol,
208 + struct snd_ctl_elem_value *ucontrol)
209 +{
210 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
211 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
212 + int changed = 0;
213 +
214 + if (priv->max_rate_idx != ucontrol->value.enumerated.item[0]) {
215 + changed = 1;
216 + priv->max_rate_idx = ucontrol->value.enumerated.item[0];
217 + }
218 +
219 + return changed;
220 +}
221 +
222 +static int rpi_cirrus_spdif_info(struct snd_kcontrol *kcontrol,
223 + struct snd_ctl_elem_info *uinfo)
224 +{
225 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
226 + uinfo->count = 1;
227 + return 0;
228 +}
229 +
230 +static int rpi_cirrus_spdif_playback_get(struct snd_kcontrol *kcontrol,
231 + struct snd_ctl_elem_value *ucontrol)
232 +{
233 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
234 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
235 + int i;
236 +
237 + for (i = 0; i < 4; i++)
238 + ucontrol->value.iec958.status[i] = priv->iec958_status[i];
239 +
240 + return 0;
241 +}
242 +
243 +static int rpi_cirrus_spdif_playback_put(struct snd_kcontrol *kcontrol,
244 + struct snd_ctl_elem_value *ucontrol)
245 +{
246 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
247 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
248 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
249 + unsigned char *stat = priv->iec958_status;
250 + unsigned char *ctrl_stat = ucontrol->value.iec958.status;
251 + unsigned int mask;
252 + int i, changed = 0;
253 +
254 + for (i = 0; i < 4; i++) {
255 + mask = (i == 3) ? 0x3f : 0xff;
256 + if ((ctrl_stat[i] & mask) != (stat[i] & mask)) {
257 + changed = 1;
258 + stat[i] = ctrl_stat[i] & mask;
259 + snd_soc_update_bits(wm8804_codec,
260 + WM8804_SPDTX1 + i, mask, stat[i]);
261 + }
262 + }
263 +
264 + return changed;
265 +}
266 +
267 +static int rpi_cirrus_spdif_mask_get(struct snd_kcontrol *kcontrol,
268 + struct snd_ctl_elem_value *ucontrol)
269 +{
270 + ucontrol->value.iec958.status[0] = 0xff;
271 + ucontrol->value.iec958.status[1] = 0xff;
272 + ucontrol->value.iec958.status[2] = 0xff;
273 + ucontrol->value.iec958.status[3] = 0x3f;
274 +
275 + return 0;
276 +}
277 +
278 +static int rpi_cirrus_spdif_capture_get(struct snd_kcontrol *kcontrol,
279 + struct snd_ctl_elem_value *ucontrol)
280 +{
281 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
282 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
283 + unsigned int mask;
284 + int i;
285 +
286 + for (i = 0; i < 4; i++) {
287 + mask = (i == 3) ? 0x3f : 0xff;
288 + ucontrol->value.iec958.status[i] =
289 + snd_soc_read(wm8804_codec, WM8804_RXCHAN1 + i) & mask;
290 + }
291 +
292 + return 0;
293 +}
294 +
295 +#define SPDIF_FLAG_CTRL(desc, reg, bit, invert) \
296 +{ \
297 + .access = SNDRV_CTL_ELEM_ACCESS_READ \
298 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
299 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
300 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) \
301 + desc " Flag", \
302 + .info = snd_ctl_boolean_mono_info, \
303 + .get = rpi_cirrus_spdif_status_flag_get, \
304 + .private_value = \
305 + (bit) | ((reg) << 8) | ((invert) << 16) \
306 +}
307 +
308 +static int rpi_cirrus_spdif_status_flag_get(struct snd_kcontrol *kcontrol,
309 + struct snd_ctl_elem_value *ucontrol)
310 +{
311 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
312 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
313 +
314 + unsigned int bit = kcontrol->private_value & 0xff;
315 + unsigned int reg = (kcontrol->private_value >> 8) & 0xff;
316 + unsigned int invert = (kcontrol->private_value >> 16) & 0xff;
317 +
318 + bool flag = snd_soc_read(wm8804_codec, reg) & (1 << bit);
319 +
320 + ucontrol->value.integer.value[0] = invert ? !flag : flag;
321 +
322 + return 0;
323 +}
324 +
325 +static const char * const recovered_frequency_texts[] = {
326 + "176.4/192 kHz",
327 + "88.2/96 kHz",
328 + "44.1/48 kHz",
329 + "32 kHz"
330 +};
331 +
332 +#define NUM_RECOVERED_FREQUENCIES \
333 + ARRAY_SIZE(recovered_frequency_texts)
334 +
335 +static int rpi_cirrus_recovered_frequency_info(struct snd_kcontrol *kcontrol,
336 + struct snd_ctl_elem_info *uinfo)
337 +{
338 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
339 + uinfo->count = 1;
340 + uinfo->value.enumerated.items = NUM_RECOVERED_FREQUENCIES;
341 + if (uinfo->value.enumerated.item >= NUM_RECOVERED_FREQUENCIES)
342 + uinfo->value.enumerated.item = NUM_RECOVERED_FREQUENCIES - 1;
343 + strcpy(uinfo->value.enumerated.name,
344 + recovered_frequency_texts[uinfo->value.enumerated.item]);
345 + return 0;
346 +}
347 +
348 +static int rpi_cirrus_recovered_frequency_get(struct snd_kcontrol *kcontrol,
349 + struct snd_ctl_elem_value *ucontrol)
350 +{
351 + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
352 + struct snd_soc_codec *wm8804_codec = get_wm8804_runtime(card)->codec;
353 +
354 + ucontrol->value.enumerated.item[0] =
355 + (snd_soc_read(wm8804_codec, WM8804_SPDSTAT) >> 4) & 0x03;
356 + return 0;
357 +}
358 +
359 +static const struct snd_kcontrol_new rpi_cirrus_controls[] = {
360 + {
361 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
362 + .name = "Min Sample Rate",
363 + .info = rpi_cirrus_min_rate_info,
364 + .get = rpi_cirrus_min_rate_get,
365 + .put = rpi_cirrus_min_rate_put,
366 + },
367 + {
368 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
369 + .name = "Max Sample Rate",
370 + .info = rpi_cirrus_max_rate_info,
371 + .get = rpi_cirrus_max_rate_get,
372 + .put = rpi_cirrus_max_rate_put,
373 + },
374 + {
375 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
376 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
377 + .info = rpi_cirrus_spdif_info,
378 + .get = rpi_cirrus_spdif_playback_get,
379 + .put = rpi_cirrus_spdif_playback_put,
380 + },
381 + {
382 + .access = SNDRV_CTL_ELEM_ACCESS_READ
383 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
384 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
385 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
386 + .info = rpi_cirrus_spdif_info,
387 + .get = rpi_cirrus_spdif_capture_get,
388 + },
389 + {
390 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
391 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
392 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
393 + .info = rpi_cirrus_spdif_info,
394 + .get = rpi_cirrus_spdif_mask_get,
395 + },
396 + {
397 + .access = SNDRV_CTL_ELEM_ACCESS_READ
398 + | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
399 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
400 + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE)
401 + "Recovered Frequency",
402 + .info = rpi_cirrus_recovered_frequency_info,
403 + .get = rpi_cirrus_recovered_frequency_get,
404 + },
405 + SPDIF_FLAG_CTRL("Audio", WM8804_SPDSTAT, 0, 1),
406 + SPDIF_FLAG_CTRL("Non-PCM", WM8804_SPDSTAT, 1, 0),
407 + SPDIF_FLAG_CTRL("Copyright", WM8804_SPDSTAT, 2, 1),
408 + SPDIF_FLAG_CTRL("De-Emphasis", WM8804_SPDSTAT, 3, 0),
409 + SPDIF_FLAG_CTRL("Lock", WM8804_SPDSTAT, 6, 1),
410 + SPDIF_FLAG_CTRL("Invalid", WM8804_INTSTAT, 1, 0),
411 + SPDIF_FLAG_CTRL("TransErr", WM8804_INTSTAT, 3, 0),
412 +};
413 +
414 +static const char * const linein_micbias_texts[] = {
415 + "off", "on",
416 +};
417 +
418 +static SOC_ENUM_SINGLE_VIRT_DECL(linein_micbias_enum,
419 + linein_micbias_texts);
420 +
421 +static const struct snd_kcontrol_new linein_micbias_mux =
422 + SOC_DAPM_ENUM("Route", linein_micbias_enum);
423 +
424 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
425 + struct snd_kcontrol *kcontrol, int event);
426 +
427 +const struct snd_soc_dapm_widget rpi_cirrus_dapm_widgets[] = {
428 + SND_SOC_DAPM_MIC("DMIC", NULL),
429 + SND_SOC_DAPM_MIC("Headset Mic", NULL),
430 + SND_SOC_DAPM_INPUT("Line Input"),
431 + SND_SOC_DAPM_MIC("Line Input with Micbias", NULL),
432 + SND_SOC_DAPM_MUX("Line Input Micbias", SND_SOC_NOPM, 0, 0,
433 + &linein_micbias_mux),
434 + SND_SOC_DAPM_INPUT("dummy SPDIF in"),
435 + SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0, NULL, 0,
436 + rpi_cirrus_spdif_rx_enable_event,
437 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
438 + SND_SOC_DAPM_INPUT("Dummy Input"),
439 + SND_SOC_DAPM_OUTPUT("Dummy Output"),
440 +};
441 +
442 +const struct snd_soc_dapm_route rpi_cirrus_dapm_routes[] = {
443 + { "IN1L", NULL, "Headset Mic" },
444 + { "IN1R", NULL, "Headset Mic" },
445 + { "Headset Mic", NULL, "MICBIAS1" },
446 +
447 + { "IN2L", NULL, "DMIC" },
448 + { "IN2R", NULL, "DMIC" },
449 + { "DMIC", NULL, "MICBIAS2" },
450 +
451 + { "IN3L", NULL, "Line Input Micbias" },
452 + { "IN3R", NULL, "Line Input Micbias" },
453 +
454 + { "Line Input Micbias", "off", "Line Input" },
455 + { "Line Input Micbias", "on", "Line Input with Micbias" },
456 +
457 + /* Make sure MICVDD is enabled, otherwise we get noise */
458 + { "Line Input", NULL, "MICVDD" },
459 + { "Line Input with Micbias", NULL, "MICBIAS3" },
460 +
461 + /* Dummy routes to check whether SPDIF RX is enabled or not */
462 + {"dummy SPDIFRX", NULL, "dummy SPDIF in"},
463 + {"AIFTX", NULL, "dummy SPDIFRX"},
464 +
465 + /*
466 + * Dummy routes to keep wm5102 from staying off on
467 + * playback/capture if all mixers are off.
468 + */
469 + { "Dummy Output", NULL, "AIF1RX1" },
470 + { "Dummy Output", NULL, "AIF1RX2" },
471 + { "AIF1TX1", NULL, "Dummy Input" },
472 + { "AIF1TX2", NULL, "Dummy Input" },
473 +};
474 +
475 +static int rpi_cirrus_clear_flls(struct snd_soc_card *card,
476 + struct snd_soc_codec *wm5102_codec) {
477 +
478 + int ret1, ret2;
479 +
480 + ret1 = snd_soc_codec_set_pll(wm5102_codec,
481 + WM5102_FLL1, ARIZONA_FLL_SRC_NONE, 0, 0);
482 + ret2 = snd_soc_codec_set_pll(wm5102_codec,
483 + WM5102_FLL1_REFCLK, ARIZONA_FLL_SRC_NONE, 0, 0);
484 +
485 + if (ret1) {
486 + dev_warn(card->dev,
487 + "setting FLL1 to zero failed: %d\n", ret1);
488 + return ret1;
489 + }
490 + if (ret2) {
491 + dev_warn(card->dev,
492 + "setting FLL1_REFCLK to zero failed: %d\n", ret2);
493 + return ret2;
494 + }
495 + return 0;
496 +}
497 +
498 +static int rpi_cirrus_set_fll(struct snd_soc_card *card,
499 + struct snd_soc_codec *wm5102_codec, unsigned int clk_freq)
500 +{
501 + int ret = snd_soc_codec_set_pll(wm5102_codec,
502 + WM5102_FLL1,
503 + ARIZONA_CLK_SRC_MCLK1,
504 + WM8804_CLKOUT_HZ,
505 + clk_freq);
506 + if (ret)
507 + dev_err(card->dev, "Failed to set FLL1 to %d: %d\n",
508 + clk_freq, ret);
509 +
510 + usleep_range(1000, 2000);
511 + return ret;
512 +}
513 +
514 +static int rpi_cirrus_set_fll_refclk(struct snd_soc_card *card,
515 + struct snd_soc_codec *wm5102_codec,
516 + unsigned int clk_freq, unsigned int aif2_freq)
517 +{
518 + int ret = snd_soc_codec_set_pll(wm5102_codec,
519 + WM5102_FLL1_REFCLK,
520 + ARIZONA_CLK_SRC_MCLK1,
521 + WM8804_CLKOUT_HZ,
522 + clk_freq);
523 + if (ret) {
524 + dev_err(card->dev,
525 + "Failed to set FLL1_REFCLK to %d: %d\n",
526 + clk_freq, ret);
527 + return ret;
528 + }
529 +
530 + ret = snd_soc_codec_set_pll(wm5102_codec,
531 + WM5102_FLL1,
532 + ARIZONA_CLK_SRC_AIF2BCLK,
533 + aif2_freq, clk_freq);
534 + if (ret)
535 + dev_err(card->dev,
536 + "Failed to set FLL1 with Sync Clock %d to %d: %d\n",
537 + aif2_freq, clk_freq, ret);
538 +
539 + usleep_range(1000, 2000);
540 + return ret;
541 +}
542 +
543 +static int rpi_cirrus_spdif_rx_enable_event(struct snd_soc_dapm_widget *w,
544 + struct snd_kcontrol *kcontrol, int event)
545 +{
546 + struct snd_soc_card *card = w->dapm->card;
547 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
548 + struct snd_soc_codec *wm5102_codec = get_wm5102_runtime(card)->codec;
549 +
550 + unsigned int clk_freq, aif2_freq;
551 + int ret = 0;
552 +
553 + switch (event) {
554 + case SND_SOC_DAPM_POST_PMU:
555 + mutex_lock(&priv->lock);
556 +
557 + /* Enable sync path in case of SPDIF capture use case */
558 +
559 + clk_freq = calc_sysclk(priv->card_rate);
560 + aif2_freq = 64 * priv->card_rate;
561 +
562 + dev_dbg(card->dev,
563 + "spdif_rx: changing FLL1 to use Ref Clock clk: %d spdif: %d\n",
564 + clk_freq, aif2_freq);
565 +
566 + ret = rpi_cirrus_clear_flls(card, wm5102_codec);
567 + if (ret) {
568 + dev_err(card->dev, "spdif_rx: failed to clear FLLs\n");
569 + goto out;
570 + }
571 +
572 + ret = rpi_cirrus_set_fll_refclk(card, wm5102_codec,
573 + clk_freq, aif2_freq);
574 +
575 + if (ret) {
576 + dev_err(card->dev, "spdif_rx: failed to set FLLs\n");
577 + goto out;
578 + }
579 +
580 + /* set to negative to indicate we're doing spdif rx */
581 + priv->fll1_freq = -clk_freq;
582 + priv->sync_path_enable = 1;
583 + break;
584 +
585 + case SND_SOC_DAPM_POST_PMD:
586 + mutex_lock(&priv->lock);
587 + priv->sync_path_enable = 0;
588 + break;
589 +
590 + default:
591 + return 0;
592 + }
593 +
594 +out:
595 + mutex_unlock(&priv->lock);
596 + return ret;
597 +}
598 +
599 +static int rpi_cirrus_set_bias_level(struct snd_soc_card *card,
600 + struct snd_soc_dapm_context *dapm,
601 + enum snd_soc_bias_level level)
602 +{
603 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
604 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
605 + struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec;
606 +
607 + int ret = 0;
608 + unsigned int clk_freq;
609 +
610 + if (dapm->dev != wm5102_runtime->codec_dai->dev)
611 + return 0;
612 +
613 + switch (level) {
614 + case SND_SOC_BIAS_PREPARE:
615 + if (dapm->bias_level == SND_SOC_BIAS_ON)
616 + break;
617 +
618 + mutex_lock(&priv->lock);
619 +
620 + if (!priv->sync_path_enable) {
621 + clk_freq = calc_sysclk(priv->card_rate);
622 +
623 + dev_dbg(card->dev,
624 + "set_bias: changing FLL1 from %d to %d\n",
625 + priv->fll1_freq, clk_freq);
626 +
627 + ret = rpi_cirrus_set_fll(card, wm5102_codec, clk_freq);
628 + if (ret)
629 + dev_err(card->dev,
630 + "set_bias: Failed to set FLL1\n");
631 + else
632 + priv->fll1_freq = clk_freq;
633 + }
634 + mutex_unlock(&priv->lock);
635 + break;
636 + default:
637 + break;
638 + }
639 +
640 + return ret;
641 +}
642 +
643 +static int rpi_cirrus_set_bias_level_post(struct snd_soc_card *card,
644 + struct snd_soc_dapm_context *dapm,
645 + enum snd_soc_bias_level level)
646 +{
647 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
648 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
649 + struct snd_soc_codec *wm5102_codec = wm5102_runtime->codec;
650 +
651 + if (dapm->dev != wm5102_runtime->codec_dai->dev)
652 + return 0;
653 +
654 + switch (level) {
655 + case SND_SOC_BIAS_STANDBY:
656 + mutex_lock(&priv->lock);
657 +
658 + dev_dbg(card->dev,
659 + "set_bias_post: changing FLL1 from %d to off\n",
660 + priv->fll1_freq);
661 +
662 + if (rpi_cirrus_clear_flls(card, wm5102_codec))
663 + dev_err(card->dev,
664 + "set_bias_post: failed to clear FLLs\n");
665 + else
666 + priv->fll1_freq = 0;
667 +
668 + mutex_unlock(&priv->lock);
669 +
670 + break;
671 + default:
672 + break;
673 + }
674 +
675 + return 0;
676 +}
677 +
678 +static int rpi_cirrus_set_wm8804_pll(struct snd_soc_card *card,
679 + struct snd_soc_dai *wm8804_dai, unsigned int rate)
680 +{
681 + int ret;
682 +
683 + /* use 256fs */
684 + unsigned int clk_freq = rate * 256;
685 +
686 + ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0,
687 + WM8804_CLKOUT_HZ, clk_freq);
688 + if (ret) {
689 + dev_err(card->dev,
690 + "Failed to set WM8804 PLL to %d: %d\n", clk_freq, ret);
691 + return ret;
692 + }
693 +
694 + /* Set MCLK as PLL Output */
695 + ret = snd_soc_dai_set_sysclk(wm8804_dai,
696 + WM8804_TX_CLKSRC_PLL, clk_freq, 0);
697 + if (ret) {
698 + dev_err(card->dev,
699 + "Failed to set MCLK as PLL Output: %d\n", ret);
700 + return ret;
701 + }
702 +
703 + return ret;
704 +}
705 +
706 +static int rpi_cirrus_startup(struct snd_pcm_substream *substream)
707 +{
708 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
709 + struct snd_soc_card *card = rtd->card;
710 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
711 + unsigned int min_rate = min_rates[priv->min_rate_idx].value;
712 + unsigned int max_rate = max_rates[priv->max_rate_idx].value;
713 +
714 + if (min_rate || max_rate) {
715 + if (max_rate == 0)
716 + max_rate = UINT_MAX;
717 +
718 + dev_dbg(card->dev,
719 + "startup: limiting rate to %u-%u\n",
720 + min_rate, max_rate);
721 +
722 + snd_pcm_hw_constraint_minmax(substream->runtime,
723 + SNDRV_PCM_HW_PARAM_RATE, min_rate, max_rate);
724 + }
725 +
726 + return 0;
727 +}
728 +
729 +static struct snd_soc_pcm_stream rpi_cirrus_dai_link2_params = {
730 + .formats = SNDRV_PCM_FMTBIT_S24_LE,
731 + .channels_min = 2,
732 + .channels_max = 2,
733 + .rate_min = RPI_CIRRUS_DEFAULT_RATE,
734 + .rate_max = RPI_CIRRUS_DEFAULT_RATE,
735 +};
736 +
737 +static int rpi_cirrus_hw_params(struct snd_pcm_substream *substream,
738 + struct snd_pcm_hw_params *params)
739 +{
740 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
741 + struct snd_soc_card *card = rtd->card;
742 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
743 + struct snd_soc_dai *bcm_i2s_dai = rtd->cpu_dai;
744 + struct snd_soc_codec *wm5102_codec = rtd->codec;
745 + struct snd_soc_dai *wm8804_dai = get_wm8804_runtime(card)->codec_dai;
746 +
747 + int ret;
748 +
749 + unsigned int width = snd_pcm_format_physical_width(
750 + params_format(params));
751 + unsigned int rate = params_rate(params);
752 + unsigned int clk_freq = calc_sysclk(rate);
753 +
754 + mutex_lock(&priv->lock);
755 +
756 + dev_dbg(card->dev, "hw_params: setting rate to %d\n", rate);
757 +
758 + ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, 2 * width);
759 + if (ret) {
760 + dev_err(card->dev, "set_bclk_ratio failed: %d\n", ret);
761 + goto out;
762 + }
763 +
764 + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, 0x03, 0x03, 2, width);
765 + if (ret) {
766 + dev_err(card->dev, "set_tdm_slot failed: %d\n", ret);
767 + goto out;
768 + }
769 +
770 + /* WM8804 supports sample rates from 32k only */
771 + if (rate >= 32000) {
772 + ret = rpi_cirrus_set_wm8804_pll(card, wm8804_dai, rate);
773 + if (ret)
774 + goto out;
775 + }
776 +
777 + ret = snd_soc_codec_set_sysclk(wm5102_codec,
778 + ARIZONA_CLK_SYSCLK,
779 + ARIZONA_CLK_SRC_FLL1,
780 + clk_freq,
781 + SND_SOC_CLOCK_IN);
782 + if (ret) {
783 + dev_err(card->dev, "Failed to set SYSCLK: %d\n", ret);
784 + goto out;
785 + }
786 +
787 + if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) {
788 + dev_dbg(card->dev,
789 + "hw_params: changing FLL1 from %d to %d\n",
790 + priv->fll1_freq, clk_freq);
791 +
792 + if (rpi_cirrus_clear_flls(card, wm5102_codec)) {
793 + dev_err(card->dev, "hw_params: failed to clear FLLs\n");
794 + goto out;
795 + }
796 +
797 + if (rpi_cirrus_set_fll(card, wm5102_codec, clk_freq)) {
798 + dev_err(card->dev, "hw_params: failed to set FLL\n");
799 + goto out;
800 + }
801 +
802 + priv->fll1_freq = clk_freq;
803 + }
804 +
805 + priv->card_rate = rate;
806 + rpi_cirrus_dai_link2_params.rate_min = rate;
807 + rpi_cirrus_dai_link2_params.rate_max = rate;
808 +
809 + priv->params_set |= 1 << substream->stream;
810 +
811 +out:
812 + mutex_unlock(&priv->lock);
813 +
814 + return ret;
815 +}
816 +
817 +static int rpi_cirrus_hw_free(struct snd_pcm_substream *substream)
818 +{
819 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
820 + struct snd_soc_card *card = rtd->card;
821 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
822 + struct snd_soc_codec *wm5102_codec = rtd->codec;
823 + int ret;
824 + unsigned int old_params_set = priv->params_set;
825 +
826 + priv->params_set &= ~(1 << substream->stream);
827 +
828 + /* disable sysclk if this was the last open stream */
829 + if (priv->params_set == 0 && old_params_set) {
830 + dev_dbg(card->dev,
831 + "hw_free: Setting SYSCLK to Zero\n");
832 +
833 + ret = snd_soc_codec_set_sysclk(wm5102_codec,
834 + ARIZONA_CLK_SYSCLK,
835 + ARIZONA_CLK_SRC_FLL1,
836 + 0,
837 + SND_SOC_CLOCK_IN);
838 + if (ret)
839 + dev_err(card->dev,
840 + "hw_free: Failed to set SYSCLK to Zero: %d\n",
841 + ret);
842 + }
843 + return 0;
844 +}
845 +
846 +static int rpi_cirrus_init_wm5102(struct snd_soc_pcm_runtime *rtd)
847 +{
848 + struct snd_soc_codec *codec = rtd->codec;
849 + int ret;
850 +
851 + /* no 32kHz input, derive it from sysclk if needed */
852 + snd_soc_update_bits(codec,
853 + ARIZONA_CLOCK_32K_1, ARIZONA_CLK_32K_SRC_MASK, 2);
854 +
855 + if (rpi_cirrus_clear_flls(rtd->card, codec))
856 + dev_warn(rtd->card->dev,
857 + "init_wm5102: failed to clear FLLs\n");
858 +
859 + ret = snd_soc_codec_set_sysclk(codec,
860 + ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1,
861 + 0, SND_SOC_CLOCK_IN);
862 + if (ret) {
863 + dev_err(rtd->card->dev,
864 + "Failed to set SYSCLK to Zero: %d\n", ret);
865 + return ret;
866 + }
867 +
868 + return 0;
869 +}
870 +
871 +static int rpi_cirrus_init_wm8804(struct snd_soc_pcm_runtime *rtd)
872 +{
873 + struct snd_soc_codec *codec = rtd->codec;
874 + struct snd_soc_dai *codec_dai = rtd->codec_dai;
875 + struct snd_soc_card *card = rtd->card;
876 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
877 + unsigned int mask;
878 + int i, ret;
879 +
880 + for (i = 0; i < 4; i++) {
881 + mask = (i == 3) ? 0x3f : 0xff;
882 + priv->iec958_status[i] =
883 + snd_soc_read(codec, WM8804_SPDTX1 + i) & mask;
884 + }
885 +
886 + /* Setup for 256fs */
887 + ret = snd_soc_dai_set_clkdiv(codec_dai,
888 + WM8804_MCLK_DIV, WM8804_MCLKDIV_256FS);
889 + if (ret) {
890 + dev_err(card->dev,
891 + "init_wm8804: Failed to set MCLK_DIV to 256fs: %d\n",
892 + ret);
893 + return ret;
894 + }
895 +
896 + /* Output OSC on CLKOUT */
897 + ret = snd_soc_dai_set_sysclk(codec_dai,
898 + WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0);
899 + if (ret)
900 + dev_err(card->dev,
901 + "init_wm8804: Failed to set CLKOUT as OSC Frequency: %d\n",
902 + ret);
903 +
904 + /* Init PLL with default samplerate */
905 + ret = rpi_cirrus_set_wm8804_pll(card, codec_dai,
906 + RPI_CIRRUS_DEFAULT_RATE);
907 + if (ret)
908 + dev_err(card->dev,
909 + "init_wm8804: Failed to setup PLL for %dHz: %d\n",
910 + RPI_CIRRUS_DEFAULT_RATE, ret);
911 +
912 + return ret;
913 +}
914 +
915 +static struct snd_soc_ops rpi_cirrus_ops = {
916 + .startup = rpi_cirrus_startup,
917 + .hw_params = rpi_cirrus_hw_params,
918 + .hw_free = rpi_cirrus_hw_free,
919 +};
920 +
921 +static struct snd_soc_dai_link rpi_cirrus_dai[] = {
922 + [DAI_WM5102] = {
923 + .name = "WM5102",
924 + .stream_name = "WM5102 AiFi",
925 + .codec_dai_name = "wm5102-aif1",
926 + .codec_name = "wm5102-codec",
927 + .dai_fmt = SND_SOC_DAIFMT_I2S
928 + | SND_SOC_DAIFMT_NB_NF
929 + | SND_SOC_DAIFMT_CBM_CFM,
930 + .ops = &rpi_cirrus_ops,
931 + .init = rpi_cirrus_init_wm5102,
932 + },
933 + [DAI_WM8804] = {
934 + .name = "WM5102 SPDIF",
935 + .stream_name = "SPDIF Tx/Rx",
936 + .cpu_dai_name = "wm5102-aif2",
937 + .codec_dai_name = "wm8804-spdif",
938 + .codec_name = "wm8804.1-003b",
939 + .dai_fmt = SND_SOC_DAIFMT_I2S
940 + | SND_SOC_DAIFMT_NB_NF
941 + | SND_SOC_DAIFMT_CBM_CFM,
942 + .ignore_suspend = 1,
943 + .params = &rpi_cirrus_dai_link2_params,
944 + .init = rpi_cirrus_init_wm8804,
945 + },
946 +};
947 +
948 +
949 +static int rpi_cirrus_late_probe(struct snd_soc_card *card)
950 +{
951 + struct rpi_cirrus_priv *priv = snd_soc_card_get_drvdata(card);
952 + struct snd_soc_pcm_runtime *wm5102_runtime = get_wm5102_runtime(card);
953 + struct snd_soc_pcm_runtime *wm8804_runtime = get_wm8804_runtime(card);
954 + int ret;
955 +
956 + dev_dbg(card->dev, "iec958_bits: %02x %02x %02x %02x\n",
957 + priv->iec958_status[0],
958 + priv->iec958_status[1],
959 + priv->iec958_status[2],
960 + priv->iec958_status[3]);
961 +
962 + ret = snd_soc_dai_set_sysclk(
963 + wm5102_runtime->codec_dai, ARIZONA_CLK_SYSCLK, 0, 0);
964 + if (ret) {
965 + dev_err(card->dev,
966 + "Failed to set WM5102 codec dai clk domain: %d\n", ret);
967 + return ret;
968 + }
969 +
970 + ret = snd_soc_dai_set_sysclk(
971 + wm8804_runtime->cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0);
972 + if (ret)
973 + dev_err(card->dev,
974 + "Failed to set WM8804 codec dai clk domain: %d\n", ret);
975 +
976 + return ret;
977 +}
978 +
979 +/* audio machine driver */
980 +static struct snd_soc_card rpi_cirrus_card = {
981 + .name = "RPi-Cirrus",
982 + .driver_name = "RPiCirrus",
983 + .owner = THIS_MODULE,
984 + .dai_link = rpi_cirrus_dai,
985 + .num_links = ARRAY_SIZE(rpi_cirrus_dai),
986 + .late_probe = rpi_cirrus_late_probe,
987 + .controls = rpi_cirrus_controls,
988 + .num_controls = ARRAY_SIZE(rpi_cirrus_controls),
989 + .dapm_widgets = rpi_cirrus_dapm_widgets,
990 + .num_dapm_widgets = ARRAY_SIZE(rpi_cirrus_dapm_widgets),
991 + .dapm_routes = rpi_cirrus_dapm_routes,
992 + .num_dapm_routes = ARRAY_SIZE(rpi_cirrus_dapm_routes),
993 + .set_bias_level = rpi_cirrus_set_bias_level,
994 + .set_bias_level_post = rpi_cirrus_set_bias_level_post,
995 +};
996 +
997 +static int rpi_cirrus_probe(struct platform_device *pdev)
998 +{
999 + int ret = 0;
1000 + struct rpi_cirrus_priv *priv;
1001 + struct device_node *i2s_node;
1002 +
1003 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1004 + if (!priv)
1005 + return -ENOMEM;
1006 +
1007 + priv->min_rate_idx = 1; /* min samplerate 32kHz */
1008 + priv->card_rate = RPI_CIRRUS_DEFAULT_RATE;
1009 +
1010 + mutex_init(&priv->lock);
1011 +
1012 + snd_soc_card_set_drvdata(&rpi_cirrus_card, priv);
1013 +
1014 + if (!pdev->dev.of_node)
1015 + return -ENODEV;
1016 +
1017 + i2s_node = of_parse_phandle(
1018 + pdev->dev.of_node, "i2s-controller", 0);
1019 + if (!i2s_node) {
1020 + dev_err(&pdev->dev, "i2s-controller missing in DT\n");
1021 + return -ENODEV;
1022 + }
1023 +
1024 + rpi_cirrus_dai[DAI_WM5102].cpu_of_node = i2s_node;
1025 + rpi_cirrus_dai[DAI_WM5102].platform_of_node = i2s_node;
1026 +
1027 + rpi_cirrus_card.dev = &pdev->dev;
1028 +
1029 + ret = devm_snd_soc_register_card(&pdev->dev, &rpi_cirrus_card);
1030 + if (ret) {
1031 + if (ret == -EPROBE_DEFER)
1032 + dev_dbg(&pdev->dev,
1033 + "register card requested probe deferral\n");
1034 + else
1035 + dev_err(&pdev->dev,
1036 + "Failed to register card: %d\n", ret);
1037 + }
1038 +
1039 + return ret;
1040 +}
1041 +
1042 +static const struct of_device_id rpi_cirrus_of_match[] = {
1043 + { .compatible = "wlf,rpi-cirrus", },
1044 + {},
1045 +};
1046 +MODULE_DEVICE_TABLE(of, rpi_cirrus_of_match);
1047 +
1048 +static struct platform_driver rpi_cirrus_driver = {
1049 + .driver = {
1050 + .name = "snd-rpi-cirrus",
1051 + .of_match_table = of_match_ptr(rpi_cirrus_of_match),
1052 + },
1053 + .probe = rpi_cirrus_probe,
1054 +};
1055 +
1056 +module_platform_driver(rpi_cirrus_driver);
1057 +
1058 +MODULE_AUTHOR("Matthias Reichl <hias@horus.com>");
1059 +MODULE_DESCRIPTION("ASoC driver for Cirrus Logic Audio Card");
1060 +MODULE_LICENSE("GPL");