blob: d0d1e28757278b8b9e467f583d087b57720b5e34 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From eecd29a4a5ede49427e48ea27e372b96d11f3d04 Mon Sep 17 00:00:00 2001
2From: Johannes Krude <johannes@krude.de>
3Date: Sat, 16 Nov 2019 13:14:43 +0100
4Subject: [PATCH] Allow simultaneous use of JustBoom DAC and Digi
5
6Signed-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");