bcm27xx: update patches from RPi foundation
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0364-Allow-simultaneous-use-of-JustBoom-DAC-and-Digi.patch
1 From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001
2 From: Johannes Krude <johannes@krude.de>
3 Date: Sat, 16 Nov 2019 13:14:43 +0100
4 Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
5
6 Signed-off-by: Johannes Krude <johannes@krude.de>
7 ---
8 arch/arm/boot/dts/overlays/Makefile | 1 +
9 arch/arm/boot/dts/overlays/README | 20 ++
10 .../dts/overlays/justboom-both-overlay.dts | 65 +++++
11 sound/soc/bcm/Kconfig | 12 +
12 sound/soc/bcm/Makefile | 2 +
13 sound/soc/bcm/justboom-both.c | 266 ++++++++++++++++++
14 11 files changed, 371 insertions(+)
15 create mode 100644 arch/arm/boot/dts/overlays/justboom-both-overlay.dts
16 create mode 100644 sound/soc/bcm/justboom-both.c
17
18 --- a/arch/arm/boot/dts/overlays/Makefile
19 +++ b/arch/arm/boot/dts/overlays/Makefile
20 @@ -86,6 +86,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
21 iqaudio-digi-wm8804-audio.dtbo \
22 irs1125.dtbo \
23 jedec-spi-nor.dtbo \
24 + justboom-both.dtbo \
25 justboom-dac.dtbo \
26 justboom-digi.dtbo \
27 ltc294x.dtbo \
28 --- a/arch/arm/boot/dts/overlays/README
29 +++ b/arch/arm/boot/dts/overlays/README
30 @@ -1388,6 +1388,26 @@ Params: flash-spi<n>-<m> Enables
31 on SPI<n>, CS#<m>.
32
33
34 +Name: justboom-both
35 +Info: Simultaneous usage of an justboom-dac and justboom-digi based
36 + card
37 +Load: dtoverlay=justboom-both,<param>=<val>
38 +Params: 24db_digital_gain Allow gain to be applied via the PCM512x codec
39 + Digital volume control. Enable with
40 + "dtoverlay=justboom-dac,24db_digital_gain"
41 + (The default behaviour is that the Digital
42 + volume control is limited to a maximum of
43 + 0dB. ie. it can attenuate but not provide
44 + gain. For most users, this will be desired
45 + as it will prevent clipping. By appending
46 + the 24dB_digital_gain parameter, the Digital
47 + volume control will allow up to 24dB of
48 + gain. If this parameter is enabled, it is the
49 + responsibility of the user to ensure that
50 + the Digital volume control is set to a value
51 + that does not result in clipping/distortion!)
52 +
53 +
54 Name: justboom-dac
55 Info: Configures the JustBoom DAC HAT, Amp HAT, DAC Zero and Amp Zero audio
56 cards
57 --- /dev/null
58 +++ b/arch/arm/boot/dts/overlays/justboom-both-overlay.dts
59 @@ -0,0 +1,65 @@
60 +// SPDX-License-Identifier: GPL-2.0
61 +// Definitions for JustBoom Both (Digi+DAC)
62 +/dts-v1/;
63 +/plugin/;
64 +
65 +/ {
66 + compatible = "brcm,bcm2835";
67 +
68 + fragment@0 {
69 + target = <&i2s>;
70 + __overlay__ {
71 + status = "okay";
72 + };
73 + };
74 +
75 + fragment@1 {
76 + target = <&i2c1>;
77 + __overlay__ {
78 + #address-cells = <1>;
79 + #size-cells = <0>;
80 + status = "okay";
81 +
82 + wm8804@3b {
83 + #sound-dai-cells = <0>;
84 + compatible = "wlf,wm8804";
85 + reg = <0x3b>;
86 + PVDD-supply = <&vdd_3v3_reg>;
87 + DVDD-supply = <&vdd_3v3_reg>;
88 + status = "okay";
89 + };
90 + };
91 + };
92 +
93 + fragment@2 {
94 + target = <&i2c1>;
95 + __overlay__ {
96 + #address-cells = <1>;
97 + #size-cells = <0>;
98 + status = "okay";
99 +
100 + pcm5122@4d {
101 + #sound-dai-cells = <0>;
102 + compatible = "ti,pcm5122";
103 + reg = <0x4d>;
104 + AVDD-supply = <&vdd_3v3_reg>;
105 + DVDD-supply = <&vdd_3v3_reg>;
106 + CPVDD-supply = <&vdd_3v3_reg>;
107 + status = "okay";
108 + };
109 + };
110 + };
111 +
112 + fragment@3 {
113 + target = <&sound>;
114 + frag3: __overlay__ {
115 + compatible = "justboom,justboom-both";
116 + i2s-controller = <&i2s>;
117 + status = "okay";
118 + };
119 + };
120 +
121 + __overrides__ {
122 + 24db_digital_gain = <&frag3>,"justboom,24db_digital_gain?";
123 + };
124 +};
125 --- a/sound/soc/bcm/Kconfig
126 +++ b/sound/soc/bcm/Kconfig
127 @@ -105,6 +105,18 @@ config SND_BCM2708_SOC_RPI_PROTO
128 help
129 Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
130
131 +config SND_BCM2708_SOC_JUSTBOOM_BOTH
132 + tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
133 + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
134 + select SND_SOC_WM8804
135 + select SND_SOC_PCM512x
136 + help
137 + Say Y or M if you want to add support for simultaneous
138 + JustBoom Digi and JustBoom DAC.
139 +
140 + This is not the right choice if you only have one but both of
141 + these cards.
142 +
143 config SND_BCM2708_SOC_JUSTBOOM_DAC
144 tristate "Support for JustBoom DAC"
145 depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
146 --- a/sound/soc/bcm/Makefile
147 +++ b/sound/soc/bcm/Makefile
148 @@ -17,6 +17,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
149 snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
150 snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
151 snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
152 +snd-soc-justboom-both-objs := justboom-both.o
153 snd-soc-justboom-dac-objs := justboom-dac.o
154 snd-soc-rpi-cirrus-objs := rpi-cirrus.o
155 snd-soc-rpi-proto-objs := rpi-proto.o
156 @@ -43,6 +44,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
157 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
158 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
159 obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
160 +obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH) += snd-soc-justboom-both.o
161 obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
162 obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
163 obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
164 --- /dev/null
165 +++ b/sound/soc/bcm/justboom-both.c
166 @@ -0,0 +1,266 @@
167 +// SPDX-License-Identifier: GPL-2.0
168 +/*
169 + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
170 + *
171 + * Authors: Johannes Krude <johannes@krude.de
172 + *
173 + * Driver for when connecting simultaneously justboom-digi and justboom-dac
174 + *
175 + * Based upon code from:
176 + * justboom-digi.c
177 + * by Milan Neskovic <info@justboom.co>
178 + * justboom-dac.c
179 + * by Milan Neskovic <info@justboom.co>
180 + *
181 + * This program is free software; you can redistribute it and/or
182 + * modify it under the terms of the GNU General Public License
183 + * version 2 as published by the Free Software Foundation.
184 + *
185 + * This program is distributed in the hope that it will be useful, but
186 + * WITHOUT ANY WARRANTY; without even the implied warranty of
187 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
188 + * General Public License for more details.
189 + */
190 +
191 +#include <linux/module.h>
192 +#include <linux/platform_device.h>
193 +
194 +#include <sound/core.h>
195 +#include <sound/pcm.h>
196 +#include <sound/pcm_params.h>
197 +#include <sound/soc.h>
198 +#include <sound/jack.h>
199 +
200 +#include "../codecs/wm8804.h"
201 +#include "../codecs/pcm512x.h"
202 +
203 +
204 +static bool digital_gain_0db_limit = true;
205 +
206 +static int snd_rpi_justboom_both_init(struct snd_soc_pcm_runtime *rtd)
207 +{
208 + struct snd_soc_component *digi = rtd->codec_dais[0]->component;
209 + struct snd_soc_component *dac = rtd->codec_dais[1]->component;
210 +
211 + /* enable TX output */
212 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
213 +
214 + snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
215 + snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
216 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
217 +
218 + if (digital_gain_0db_limit) {
219 + int ret;
220 + struct snd_soc_card *card = rtd->card;
221 +
222 + ret = snd_soc_limit_volume(card, "Digital Playback Volume",
223 + 207);
224 + if (ret < 0)
225 + dev_warn(card->dev, "Failed to set volume limit: %d\n",
226 + ret);
227 + }
228 +
229 + return 0;
230 +}
231 +
232 +static int snd_rpi_justboom_both_hw_params(struct snd_pcm_substream *substream,
233 + struct snd_pcm_hw_params *params)
234 +{
235 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
236 + struct snd_soc_dai *codec_dai = rtd->codec_dai;
237 + struct snd_soc_component *digi = rtd->codec_dais[0]->component;
238 + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
239 +
240 + int sysclk = 27000000; /* This is fixed on this board */
241 +
242 + long mclk_freq = 0;
243 + int mclk_div = 1;
244 + int sampling_freq = 1;
245 +
246 + int ret;
247 +
248 + int samplerate = params_rate(params);
249 +
250 + if (samplerate <= 96000) {
251 + mclk_freq = samplerate*256;
252 + mclk_div = WM8804_MCLKDIV_256FS;
253 + } else {
254 + mclk_freq = samplerate*128;
255 + mclk_div = WM8804_MCLKDIV_128FS;
256 + }
257 +
258 + switch (samplerate) {
259 + case 32000:
260 + sampling_freq = 0x03;
261 + break;
262 + case 44100:
263 + sampling_freq = 0x00;
264 + break;
265 + case 48000:
266 + sampling_freq = 0x02;
267 + break;
268 + case 88200:
269 + sampling_freq = 0x08;
270 + break;
271 + case 96000:
272 + sampling_freq = 0x0a;
273 + break;
274 + case 176400:
275 + sampling_freq = 0x0c;
276 + break;
277 + case 192000:
278 + sampling_freq = 0x0e;
279 + break;
280 + default:
281 + dev_err(rtd->card->dev,
282 + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
283 + samplerate);
284 + }
285 +
286 + snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
287 + snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
288 +
289 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
290 + sysclk, SND_SOC_CLOCK_OUT);
291 + if (ret < 0) {
292 + dev_err(rtd->card->dev,
293 + "Failed to set WM8804 SYSCLK: %d\n", ret);
294 + return ret;
295 + }
296 +
297 + /* Enable TX output */
298 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x4, 0x0);
299 +
300 + /* Power on */
301 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x9, 0);
302 +
303 + /* set sampling frequency status bits */
304 + snd_soc_component_update_bits(digi, WM8804_SPDTX4, 0x0f, sampling_freq);
305 +
306 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
307 +}
308 +
309 +static int snd_rpi_justboom_both_startup(struct snd_pcm_substream *substream)
310 +{
311 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
312 + struct snd_soc_component *digi = rtd->codec_dais[0]->component;
313 + struct snd_soc_component *dac = rtd->codec_dais[1]->component;
314 +
315 + /* turn on digital output */
316 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x00);
317 +
318 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
319 +
320 + return 0;
321 +}
322 +
323 +static void snd_rpi_justboom_both_shutdown(struct snd_pcm_substream *substream)
324 +{
325 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
326 + struct snd_soc_component *digi = rtd->codec_dais[0]->component;
327 + struct snd_soc_component *dac = rtd->codec_dais[1]->component;
328 +
329 + snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
330 +
331 + /* turn off output */
332 + snd_soc_component_update_bits(digi, WM8804_PWRDN, 0x3c, 0x3c);
333 +}
334 +
335 +/* machine stream operations */
336 +static struct snd_soc_ops snd_rpi_justboom_both_ops = {
337 + .hw_params = snd_rpi_justboom_both_hw_params,
338 + .startup = snd_rpi_justboom_both_startup,
339 + .shutdown = snd_rpi_justboom_both_shutdown,
340 +};
341 +
342 +SND_SOC_DAILINK_DEFS(rpi_justboom_both,
343 + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
344 + DAILINK_COMP_ARRAY(COMP_CODEC("pcm512x.1-004d", "pcm512x-hifi"),
345 + COMP_CODEC("wm8804.1-003b", "wm8804-spdif")),
346 + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
347 +
348 +static struct snd_soc_dai_link snd_rpi_justboom_both_dai[] = {
349 +{
350 + .name = "JustBoom Digi",
351 + .stream_name = "JustBoom Digi HiFi",
352 + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
353 + SND_SOC_DAIFMT_CBM_CFM,
354 + .ops = &snd_rpi_justboom_both_ops,
355 + .init = snd_rpi_justboom_both_init,
356 + SND_SOC_DAILINK_REG(rpi_justboom_both),
357 +},
358 +};
359 +
360 +/* audio machine driver */
361 +static struct snd_soc_card snd_rpi_justboom_both = {
362 + .name = "snd_rpi_justboom_both",
363 + .driver_name = "JustBoomBoth",
364 + .owner = THIS_MODULE,
365 + .dai_link = snd_rpi_justboom_both_dai,
366 + .num_links = ARRAY_SIZE(snd_rpi_justboom_both_dai),
367 +};
368 +
369 +static int snd_rpi_justboom_both_probe(struct platform_device *pdev)
370 +{
371 + int ret = 0;
372 + struct snd_soc_card *card = &snd_rpi_justboom_both;
373 +
374 + snd_rpi_justboom_both.dev = &pdev->dev;
375 +
376 + if (pdev->dev.of_node) {
377 + struct device_node *i2s_node;
378 + struct snd_soc_dai_link *dai = &snd_rpi_justboom_both_dai[0];
379 +
380 + i2s_node = of_parse_phandle(pdev->dev.of_node,
381 + "i2s-controller", 0);
382 +
383 + if (i2s_node) {
384 + int i;
385 +
386 + for (i = 0; i < card->num_links; i++) {
387 + dai->cpus->dai_name = NULL;
388 + dai->cpus->of_node = i2s_node;
389 + dai->platforms->name = NULL;
390 + dai->platforms->of_node = i2s_node;
391 + }
392 + }
393 +
394 + digital_gain_0db_limit = !of_property_read_bool(
395 + pdev->dev.of_node, "justboom,24db_digital_gain");
396 + }
397 +
398 + ret = snd_soc_register_card(card);
399 + if (ret && ret != -EPROBE_DEFER) {
400 + dev_err(&pdev->dev,
401 + "snd_soc_register_card() failed: %d\n", ret);
402 + }
403 +
404 + return ret;
405 +}
406 +
407 +static int snd_rpi_justboom_both_remove(struct platform_device *pdev)
408 +{
409 + return snd_soc_unregister_card(&snd_rpi_justboom_both);
410 +}
411 +
412 +static const struct of_device_id snd_rpi_justboom_both_of_match[] = {
413 + { .compatible = "justboom,justboom-both", },
414 + {},
415 +};
416 +MODULE_DEVICE_TABLE(of, snd_rpi_justboom_both_of_match);
417 +
418 +static struct platform_driver snd_rpi_justboom_both_driver = {
419 + .driver = {
420 + .name = "snd-rpi-justboom-both",
421 + .owner = THIS_MODULE,
422 + .of_match_table = snd_rpi_justboom_both_of_match,
423 + },
424 + .probe = snd_rpi_justboom_both_probe,
425 + .remove = snd_rpi_justboom_both_remove,
426 +};
427 +
428 +module_platform_driver(snd_rpi_justboom_both_driver);
429 +
430 +MODULE_AUTHOR("Johannes Krude <johannes@krude.de>");
431 +MODULE_DESCRIPTION("ASoC Driver for simultaneous use of JustBoom PI Digi & DAC HAT Sound Cards");
432 +MODULE_LICENSE("GPL v2");