]> git.pld-linux.org Git - packages/kernel.git/blame - rpi-wm8804.patch
just be more precise when updating shebangs
[packages/kernel.git] / rpi-wm8804.patch
CommitLineData
cb548207
JP
1--- linux-5.9.orig/sound/soc/bcm/Kconfig 2020-10-11 23:15:50.000000000 +0200
2+++ linux-5.9/sound/soc/bcm/Kconfig 2020-12-14 01:08:25.450035831 +0100
3@@ -26,3 +26,10 @@
4 DSL/PON chips (bcm63158, bcm63178)
5
6 If you don't know what to do here, say N
7+
8+config SND_BCM2708_SOC_HIFIBERRY_DIGI
9+ tristate "Support for HifiBerry Digi"
10+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
11+ select SND_SOC_WM8804
12+ help
13+ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
14--- linux-5.9.orig/sound/soc/bcm/Makefile 2020-10-11 23:15:50.000000000 +0200
15+++ linux-5.9/sound/soc/bcm/Makefile 2020-12-14 01:05:51.274295380 +0100
16@@ -12,4 +12,8 @@
17 # BCM63XX Platform Support
18 snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
19
20-obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
21\ No newline at end of file
22+obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
23+
24+snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
25+
26+obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o
27--- linux-5.9.orig/sound/soc/bcm/rpi-wm8804-soundcard.c 1970-01-01 01:00:00.000000000 +0100
28+++ linux-5.9/sound/soc/bcm/rpi-wm8804-soundcard.c 2020-12-14 01:02:38.688758934 +0100
29@@ -0,0 +1,410 @@
30+// SPDX-License-Identifier: GPL-2.0
31+/*
32+ * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
33+ *
34+ * Copyright (C) 2018 Raspberry Pi.
35+ *
36+ * Authors: Tim Gover <tim.gover@raspberrypi.org>
37+ *
38+ * Generic driver for Pi Hat WM8804 digi sounds cards
39+ *
40+ * Based upon code from:
41+ * justboom-digi.c
42+ * by Milan Neskovic <info@justboom.co>
43+ *
44+ * iqaudio_digi.c
45+ * by Daniel Matuschek <info@crazy-audio.com>
46+ *
47+ * allo-digione.c
48+ * by Baswaraj <jaikumar@cem-solutions.net>
49+ *
50+ * hifiberry-digi.c
51+ * Daniel Matuschek <info@crazy-audio.com>
52+ *
53+ * This program is free software; you can redistribute it and/or
54+ * modify it under the terms of the GNU General Public License
55+ * version 2 as published by the Free Software Foundation.
56+ *
57+ * This program is distributed in the hope that it will be useful, but
58+ * WITHOUT ANY WARRANTY; without even the implied warranty of
59+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
60+ * General Public License for more details.
61+ */
62+
63+#include <linux/gpio/consumer.h>
64+#include <linux/platform_device.h>
65+#include <linux/module.h>
66+
67+#include <sound/core.h>
68+#include <sound/pcm.h>
69+#include <sound/pcm_params.h>
70+#include <sound/soc.h>
71+
72+#include "../codecs/wm8804.h"
73+
74+struct wm8804_clk_cfg {
75+ unsigned int sysclk_freq;
76+ unsigned int mclk_freq;
77+ unsigned int mclk_div;
78+};
79+
80+/* Parameters for generic functions */
81+struct snd_rpi_wm8804_drvdata {
82+ /* Required - pointer to the DAI structure */
83+ struct snd_soc_dai_link *dai;
84+ /* Required - snd_soc_card name */
85+ const char *card_name;
86+ /* Optional DT node names if card info is defined in DT */
87+ const char *card_name_dt;
88+ const char *dai_name_dt;
89+ const char *dai_stream_name_dt;
90+ /* Optional probe extension - called prior to register_card */
91+ int (*probe)(struct platform_device *pdev);
92+};
93+
94+static struct gpio_desc *snd_clk44gpio;
95+static struct gpio_desc *snd_clk48gpio;
96+static int wm8804_samplerate = 0;
97+
98+/* Forward declarations */
99+static struct snd_soc_dai_link snd_allo_digione_dai[];
100+static struct snd_soc_card snd_rpi_wm8804;
101+
102+
103+#define CLK_44EN_RATE 22579200UL
104+#define CLK_48EN_RATE 24576000UL
105+
106+static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
107+{
108+ switch (samplerate) {
109+ case 11025:
110+ case 22050:
111+ case 44100:
112+ case 88200:
113+ case 176400:
114+ gpiod_set_value_cansleep(snd_clk44gpio, 1);
115+ gpiod_set_value_cansleep(snd_clk48gpio, 0);
116+ return CLK_44EN_RATE;
117+ default:
118+ gpiod_set_value_cansleep(snd_clk48gpio, 1);
119+ gpiod_set_value_cansleep(snd_clk44gpio, 0);
120+ return CLK_48EN_RATE;
121+ }
122+}
123+
124+static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
125+ struct wm8804_clk_cfg *clk_cfg)
126+{
127+ clk_cfg->sysclk_freq = 27000000;
128+
129+ if (samplerate <= 96000 ||
130+ snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
131+ clk_cfg->mclk_freq = samplerate * 256;
132+ clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
133+ } else {
134+ clk_cfg->mclk_freq = samplerate * 128;
135+ clk_cfg->mclk_div = WM8804_MCLKDIV_128FS;
136+ }
137+
138+ if (!(IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)))
139+ clk_cfg->sysclk_freq = snd_rpi_wm8804_enable_clock(samplerate);
140+}
141+
142+static int snd_rpi_wm8804_hw_params(struct snd_pcm_substream *substream,
143+ struct snd_pcm_hw_params *params)
144+{
145+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
146+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
147+ struct snd_soc_component *component = rtd->codec_dai->component;
148+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
149+ int sampling_freq = 1;
150+ int ret;
151+ struct wm8804_clk_cfg clk_cfg;
152+ int samplerate = params_rate(params);
153+
154+ if (samplerate == wm8804_samplerate)
155+ return 0;
156+
157+ /* clear until all clocks are setup properly */
158+ wm8804_samplerate = 0;
159+
160+ snd_rpi_wm8804_clk_cfg(samplerate, &clk_cfg);
161+
162+ pr_debug("%s samplerate: %d mclk_freq: %u mclk_div: %u sysclk: %u\n",
163+ __func__, samplerate, clk_cfg.mclk_freq,
164+ clk_cfg.mclk_div, clk_cfg.sysclk_freq);
165+
166+ switch (samplerate) {
167+ case 32000:
168+ sampling_freq = 0x03;
169+ break;
170+ case 44100:
171+ sampling_freq = 0x00;
172+ break;
173+ case 48000:
174+ sampling_freq = 0x02;
175+ break;
176+ case 88200:
177+ sampling_freq = 0x08;
178+ break;
179+ case 96000:
180+ sampling_freq = 0x0a;
181+ break;
182+ case 176400:
183+ sampling_freq = 0x0c;
184+ break;
185+ case 192000:
186+ sampling_freq = 0x0e;
187+ break;
188+ default:
189+ dev_err(rtd->card->dev,
190+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
191+ samplerate);
192+ }
193+
194+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, clk_cfg.mclk_div);
195+ snd_soc_dai_set_pll(codec_dai, 0, 0,
196+ clk_cfg.sysclk_freq, clk_cfg.mclk_freq);
197+
198+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
199+ clk_cfg.sysclk_freq, SND_SOC_CLOCK_OUT);
200+ if (ret < 0) {
201+ dev_err(rtd->card->dev,
202+ "Failed to set WM8804 SYSCLK: %d\n", ret);
203+ return ret;
204+ }
205+
206+ wm8804_samplerate = samplerate;
207+
208+ /* set sampling frequency status bits */
209+ snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f,
210+ sampling_freq);
211+
212+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
213+}
214+
215+static struct snd_soc_ops snd_rpi_wm8804_ops = {
216+ .hw_params = snd_rpi_wm8804_hw_params,
217+};
218+
219+SND_SOC_DAILINK_DEFS(justboom_digi,
220+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
221+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
222+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
223+
224+static struct snd_soc_dai_link snd_justboom_digi_dai[] = {
225+{
226+ .name = "JustBoom Digi",
227+ .stream_name = "JustBoom Digi HiFi",
228+ SND_SOC_DAILINK_REG(justboom_digi),
229+},
230+};
231+
232+static struct snd_rpi_wm8804_drvdata drvdata_justboom_digi = {
233+ .card_name = "snd_rpi_justboom_digi",
234+ .dai = snd_justboom_digi_dai,
235+};
236+
237+SND_SOC_DAILINK_DEFS(iqaudio_digi,
238+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
239+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
240+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
241+
242+static struct snd_soc_dai_link snd_iqaudio_digi_dai[] = {
243+{
244+ .name = "IQAudIO Digi",
245+ .stream_name = "IQAudIO Digi HiFi",
246+ SND_SOC_DAILINK_REG(iqaudio_digi),
247+},
248+};
249+
250+static struct snd_rpi_wm8804_drvdata drvdata_iqaudio_digi = {
251+ .card_name = "IQAudIODigi",
252+ .dai = snd_iqaudio_digi_dai,
253+ .card_name_dt = "wm8804-digi,card-name",
254+ .dai_name_dt = "wm8804-digi,dai-name",
255+ .dai_stream_name_dt = "wm8804-digi,dai-stream-name",
256+};
257+
258+static int snd_allo_digione_probe(struct platform_device *pdev)
259+{
260+ pr_debug("%s\n", __func__);
261+
262+ if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) {
263+ dev_err(&pdev->dev, "devm_gpiod_get() failed\n");
264+ return -EINVAL;
265+ }
266+ return 0;
267+}
268+
269+SND_SOC_DAILINK_DEFS(allo_digione,
270+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
271+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
272+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
273+
274+static struct snd_soc_dai_link snd_allo_digione_dai[] = {
275+{
276+ .name = "Allo DigiOne",
277+ .stream_name = "Allo DigiOne HiFi",
278+ SND_SOC_DAILINK_REG(allo_digione),
279+},
280+};
281+
282+static struct snd_rpi_wm8804_drvdata drvdata_allo_digione = {
283+ .card_name = "snd_allo_digione",
284+ .dai = snd_allo_digione_dai,
285+ .probe = snd_allo_digione_probe,
286+};
287+
288+SND_SOC_DAILINK_DEFS(hifiberry_digi,
289+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
290+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
291+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
292+
293+static struct snd_soc_dai_link snd_hifiberry_digi_dai[] = {
294+{
295+ .name = "HifiBerry Digi",
296+ .stream_name = "HifiBerry Digi HiFi",
297+ SND_SOC_DAILINK_REG(hifiberry_digi),
298+},
299+};
300+
301+static int snd_hifiberry_digi_probe(struct platform_device *pdev)
302+{
303+ pr_debug("%s\n", __func__);
304+
305+ if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
306+ return 0;
307+
308+ snd_hifiberry_digi_dai->name = "HiFiBerry Digi+ Pro";
309+ snd_hifiberry_digi_dai->stream_name = "HiFiBerry Digi+ Pro HiFi";
310+ return 0;
311+}
312+
313+static struct snd_rpi_wm8804_drvdata drvdata_hifiberry_digi = {
314+ .card_name = "snd_rpi_hifiberry_digi",
315+ .dai = snd_hifiberry_digi_dai,
316+ .probe = snd_hifiberry_digi_probe,
317+};
318+
319+static const struct of_device_id snd_rpi_wm8804_of_match[] = {
320+ { .compatible = "justboom,justboom-digi",
321+ .data = (void *) &drvdata_justboom_digi },
322+ { .compatible = "iqaudio,wm8804-digi",
323+ .data = (void *) &drvdata_iqaudio_digi },
324+ { .compatible = "allo,allo-digione",
325+ .data = (void *) &drvdata_allo_digione },
326+ { .compatible = "hifiberry,hifiberry-digi",
327+ .data = (void *) &drvdata_hifiberry_digi },
328+ {},
329+};
330+
331+static struct snd_soc_card snd_rpi_wm8804 = {
332+ .driver_name = "RPi-WM8804",
333+ .owner = THIS_MODULE,
334+ .dai_link = NULL,
335+ .num_links = 1,
336+};
337+
338+static int snd_rpi_wm8804_probe(struct platform_device *pdev)
339+{
340+ int ret = 0;
341+ const struct of_device_id *of_id;
342+
343+ snd_rpi_wm8804.dev = &pdev->dev;
344+ of_id = of_match_node(snd_rpi_wm8804_of_match, pdev->dev.of_node);
345+
346+ if (pdev->dev.of_node && of_id->data) {
347+ struct device_node *i2s_node;
348+ struct snd_rpi_wm8804_drvdata *drvdata =
349+ (struct snd_rpi_wm8804_drvdata *) of_id->data;
350+ struct snd_soc_dai_link *dai = drvdata->dai;
351+
352+ snd_soc_card_set_drvdata(&snd_rpi_wm8804, drvdata);
353+
354+ if (!dai->ops)
355+ dai->ops = &snd_rpi_wm8804_ops;
356+ if (!dai->codecs->dai_name)
357+ dai->codecs->dai_name = "wm8804-spdif";
358+ if (!dai->codecs->name)
359+ dai->codecs->name = "wm8804.1-003b";
360+ if (!dai->dai_fmt)
361+ dai->dai_fmt = SND_SOC_DAIFMT_I2S |
362+ SND_SOC_DAIFMT_NB_NF |
363+ SND_SOC_DAIFMT_CBM_CFM;
364+
365+ snd_rpi_wm8804.dai_link = dai;
366+ i2s_node = of_parse_phandle(pdev->dev.of_node,
367+ "i2s-controller", 0);
368+ if (!i2s_node) {
369+ pr_err("Failed to find i2s-controller DT node\n");
370+ return -ENODEV;
371+ }
372+
373+ snd_rpi_wm8804.name = drvdata->card_name;
374+
375+ /* If requested by in drvdata get card & DAI names from DT */
376+ if (drvdata->card_name_dt)
377+ of_property_read_string(i2s_node,
378+ drvdata->card_name_dt,
379+ &snd_rpi_wm8804.name);
380+
381+ if (drvdata->dai_name_dt)
382+ of_property_read_string(i2s_node,
383+ drvdata->dai_name_dt,
384+ &dai->name);
385+
386+ if (drvdata->dai_stream_name_dt)
387+ of_property_read_string(i2s_node,
388+ drvdata->dai_stream_name_dt,
389+ &dai->stream_name);
390+
391+ dai->cpus->of_node = i2s_node;
392+ dai->platforms->of_node = i2s_node;
393+
394+ /*
395+ * clk44gpio and clk48gpio are not required by all cards so
396+ * don't check the error status.
397+ */
398+ snd_clk44gpio =
399+ devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW);
400+
401+ snd_clk48gpio =
402+ devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW);
403+
404+ if (drvdata->probe) {
405+ ret = drvdata->probe(pdev);
406+ if (ret < 0) {
407+ dev_err(&pdev->dev, "Custom probe failed %d\n",
408+ ret);
409+ return ret;
410+ }
411+ }
412+
413+ pr_debug("%s card: %s dai: %s stream: %s\n", __func__,
414+ snd_rpi_wm8804.name,
415+ dai->name, dai->stream_name);
416+ }
417+
418+ ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_wm8804);
419+ if (ret && ret != -EPROBE_DEFER)
420+ dev_err(&pdev->dev, "Failed to register card %d\n", ret);
421+
422+ return ret;
423+}
424+
425+static struct platform_driver snd_rpi_wm8804_driver = {
426+ .driver = {
427+ .name = "snd-rpi-wm8804",
428+ .owner = THIS_MODULE,
429+ .of_match_table = snd_rpi_wm8804_of_match,
430+ },
431+ .probe = snd_rpi_wm8804_probe,
432+};
433+MODULE_DEVICE_TABLE(of, snd_rpi_wm8804_of_match);
434+
435+module_platform_driver(snd_rpi_wm8804_driver);
436+
437+MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
438+MODULE_DESCRIPTION("ASoC Raspberry Pi Hat generic digi driver for WM8804 based cards");
439+MODULE_LICENSE("GPL v2");
This page took 0.0754629999999999 seconds and 4 git commands to generate.