]> git.pld-linux.org Git - packages/kernel.git/blob - rpi-sound.patch
Up to 5.15.26 (fixes SECURITY issue https://dirtypipe.cm4all.com/ - fixed in .25)
[packages/kernel.git] / rpi-sound.patch
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,22 @@
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_DAC
9 +       tristate "Support for HifiBerry DAC"
10 +       depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
11 +       select SND_SOC_PCM5102A
12 +       select SND_RPI_SIMPLE_SOUNDCARD
13 +       help
14 +         Say Y or M if you want to add support for HifiBerry DAC.
15 +
16 +config SND_RPI_SIMPLE_SOUNDCARD
17 +       tristate "Support for Raspberry Pi simple soundcards"
18 +       help
19 +         Say Y or M if you want to add support Raspbery Pi simple soundcards
20 +
21 +config SND_RPI_WM8804_SOUNDCARD
22 +       tristate "Support for Raspberry Pi generic WM8804 soundcards"
23 +       help
24 +         Say Y or M if you want to add support for the Raspberry Pi
25 +         generic driver for WM8804 based soundcards.
26 --- linux-5.9.orig/sound/soc/bcm/Makefile       2020-10-11 23:15:50.000000000 +0200
27 +++ linux-5.9/sound/soc/bcm/Makefile    2020-12-14 01:05:51.274295380 +0100
28 @@ -12,4 +12,10 @@
29  # BCM63XX Platform Support
30  snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
31  
32 -obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
33 \ No newline at end of file
34 +obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
35 +
36 +snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
37 +snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
38 +
39 +obj-$(CONFIG_SND_RPI_SIMPLE_SOUNDCARD) += snd-soc-rpi-simple-soundcard.o
40 +obj-$(CONFIG_SND_RPI_WM8804_SOUNDCARD) += snd-soc-rpi-wm8804-soundcard.o
41 --- linux-5.9.orig/sound/soc/bcm/rpi-wm8804-soundcard.c 1970-01-01 01:00:00.000000000 +0100
42 +++ linux-5.9/sound/soc/bcm/rpi-wm8804-soundcard.c      2020-12-14 01:02:38.688758934 +0100
43 @@ -0,0 +1,410 @@
44 +// SPDX-License-Identifier: GPL-2.0
45 +/*
46 + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
47 + *
48 + * Copyright (C) 2018 Raspberry Pi.
49 + *
50 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
51 + *
52 + * Generic driver for Pi Hat WM8804 digi sounds cards
53 + *
54 + * Based upon code from:
55 + * justboom-digi.c
56 + * by Milan Neskovic <info@justboom.co>
57 + *
58 + * iqaudio_digi.c
59 + * by Daniel Matuschek <info@crazy-audio.com>
60 + *
61 + * allo-digione.c
62 + * by Baswaraj <jaikumar@cem-solutions.net>
63 + *
64 + * hifiberry-digi.c
65 + * Daniel Matuschek <info@crazy-audio.com>
66 + *
67 + * This program is free software; you can redistribute it and/or
68 + * modify it under the terms of the GNU General Public License
69 + * version 2 as published by the Free Software Foundation.
70 + *
71 + * This program is distributed in the hope that it will be useful, but
72 + * WITHOUT ANY WARRANTY; without even the implied warranty of
73 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
74 + * General Public License for more details.
75 + */
76 +
77 +#include <linux/gpio/consumer.h>
78 +#include <linux/platform_device.h>
79 +#include <linux/module.h>
80 +
81 +#include <sound/core.h>
82 +#include <sound/pcm.h>
83 +#include <sound/pcm_params.h>
84 +#include <sound/soc.h>
85 +
86 +#include "../codecs/wm8804.h"
87 +
88 +struct wm8804_clk_cfg {
89 +       unsigned int sysclk_freq;
90 +       unsigned int mclk_freq;
91 +       unsigned int mclk_div;
92 +};
93 +
94 +/* Parameters for generic functions */
95 +struct snd_rpi_wm8804_drvdata {
96 +       /* Required - pointer to the DAI structure */
97 +       struct snd_soc_dai_link *dai;
98 +       /* Required - snd_soc_card name */
99 +       const char *card_name;
100 +       /* Optional DT node names if card info is defined in DT */
101 +       const char *card_name_dt;
102 +       const char *dai_name_dt;
103 +       const char *dai_stream_name_dt;
104 +       /* Optional probe extension - called prior to register_card */
105 +       int (*probe)(struct platform_device *pdev);
106 +};
107 +
108 +static struct gpio_desc *snd_clk44gpio;
109 +static struct gpio_desc *snd_clk48gpio;
110 +static int wm8804_samplerate = 0;
111 +
112 +/* Forward declarations */
113 +static struct snd_soc_dai_link snd_allo_digione_dai[];
114 +static struct snd_soc_card snd_rpi_wm8804;
115 +
116 +
117 +#define CLK_44EN_RATE 22579200UL
118 +#define CLK_48EN_RATE 24576000UL
119 +
120 +static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
121 +{
122 +       switch (samplerate) {
123 +       case 11025:
124 +       case 22050:
125 +       case 44100:
126 +       case 88200:
127 +       case 176400:
128 +               gpiod_set_value_cansleep(snd_clk44gpio, 1);
129 +               gpiod_set_value_cansleep(snd_clk48gpio, 0);
130 +               return CLK_44EN_RATE;
131 +       default:
132 +               gpiod_set_value_cansleep(snd_clk48gpio, 1);
133 +               gpiod_set_value_cansleep(snd_clk44gpio, 0);
134 +               return CLK_48EN_RATE;
135 +       }
136 +}
137 +
138 +static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
139 +               struct wm8804_clk_cfg *clk_cfg)
140 +{
141 +       clk_cfg->sysclk_freq = 27000000;
142 +
143 +       if (samplerate <= 96000 ||
144 +           snd_rpi_wm8804.dai_link == snd_allo_digione_dai) {
145 +               clk_cfg->mclk_freq = samplerate * 256;
146 +               clk_cfg->mclk_div = WM8804_MCLKDIV_256FS;
147 +       } else {
148 +               clk_cfg->mclk_freq = samplerate * 128;
149 +               clk_cfg->mclk_div = WM8804_MCLKDIV_128FS;
150 +       }
151 +
152 +       if (!(IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)))
153 +               clk_cfg->sysclk_freq = snd_rpi_wm8804_enable_clock(samplerate);
154 +}
155 +
156 +static int snd_rpi_wm8804_hw_params(struct snd_pcm_substream *substream,
157 +               struct snd_pcm_hw_params *params)
158 +{
159 +       struct snd_soc_pcm_runtime *rtd = substream->private_data;
160 +       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
161 +       struct snd_soc_component *component = codec_dai->component;
162 +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
163 +       int sampling_freq = 1;
164 +       int ret;
165 +       struct wm8804_clk_cfg clk_cfg;
166 +       int samplerate = params_rate(params);
167 +
168 +       if (samplerate == wm8804_samplerate)
169 +               return 0;
170 +
171 +       /* clear until all clocks are setup properly */
172 +       wm8804_samplerate = 0;
173 +
174 +       snd_rpi_wm8804_clk_cfg(samplerate, &clk_cfg);
175 +
176 +       pr_debug("%s samplerate: %d mclk_freq: %u mclk_div: %u sysclk: %u\n",
177 +                       __func__, samplerate, clk_cfg.mclk_freq,
178 +                       clk_cfg.mclk_div, clk_cfg.sysclk_freq);
179 +
180 +       switch (samplerate) {
181 +       case 32000:
182 +               sampling_freq = 0x03;
183 +               break;
184 +       case 44100:
185 +               sampling_freq = 0x00;
186 +               break;
187 +       case 48000:
188 +               sampling_freq = 0x02;
189 +               break;
190 +       case 88200:
191 +               sampling_freq = 0x08;
192 +               break;
193 +       case 96000:
194 +               sampling_freq = 0x0a;
195 +               break;
196 +       case 176400:
197 +               sampling_freq = 0x0c;
198 +               break;
199 +       case 192000:
200 +               sampling_freq = 0x0e;
201 +               break;
202 +       default:
203 +               dev_err(rtd->card->dev,
204 +               "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
205 +               samplerate);
206 +       }
207 +
208 +       snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, clk_cfg.mclk_div);
209 +       snd_soc_dai_set_pll(codec_dai, 0, 0,
210 +                       clk_cfg.sysclk_freq, clk_cfg.mclk_freq);
211 +
212 +       ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
213 +                       clk_cfg.sysclk_freq, SND_SOC_CLOCK_OUT);
214 +       if (ret < 0) {
215 +               dev_err(rtd->card->dev,
216 +               "Failed to set WM8804 SYSCLK: %d\n", ret);
217 +               return ret;
218 +       }
219 +
220 +       wm8804_samplerate = samplerate;
221 +
222 +       /* set sampling frequency status bits */
223 +       snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f,
224 +                       sampling_freq);
225 +
226 +       return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
227 +}
228 +
229 +static struct snd_soc_ops snd_rpi_wm8804_ops = {
230 +       .hw_params = snd_rpi_wm8804_hw_params,
231 +};
232 +
233 +SND_SOC_DAILINK_DEFS(justboom_digi,
234 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
235 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
236 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
237 +
238 +static struct snd_soc_dai_link snd_justboom_digi_dai[] = {
239 +{
240 +       .name        = "JustBoom Digi",
241 +       .stream_name = "JustBoom Digi HiFi",
242 +       SND_SOC_DAILINK_REG(justboom_digi),
243 +},
244 +};
245 +
246 +static struct snd_rpi_wm8804_drvdata drvdata_justboom_digi = {
247 +       .card_name            = "snd_rpi_justboom_digi",
248 +       .dai                  = snd_justboom_digi_dai,
249 +};
250 +
251 +SND_SOC_DAILINK_DEFS(iqaudio_digi,
252 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
253 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
254 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
255 +
256 +static struct snd_soc_dai_link snd_iqaudio_digi_dai[] = {
257 +{
258 +       .name        = "IQAudIO Digi",
259 +       .stream_name = "IQAudIO Digi HiFi",
260 +       SND_SOC_DAILINK_REG(iqaudio_digi),
261 +},
262 +};
263 +
264 +static struct snd_rpi_wm8804_drvdata drvdata_iqaudio_digi = {
265 +       .card_name          = "IQAudIODigi",
266 +       .dai                = snd_iqaudio_digi_dai,
267 +       .card_name_dt       = "wm8804-digi,card-name",
268 +       .dai_name_dt        = "wm8804-digi,dai-name",
269 +       .dai_stream_name_dt = "wm8804-digi,dai-stream-name",
270 +};
271 +
272 +static int snd_allo_digione_probe(struct platform_device *pdev)
273 +{
274 +       pr_debug("%s\n", __func__);
275 +
276 +       if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) {
277 +               dev_err(&pdev->dev, "devm_gpiod_get() failed\n");
278 +               return -EINVAL;
279 +       }
280 +       return 0;
281 +}
282 +
283 +SND_SOC_DAILINK_DEFS(allo_digione,
284 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
285 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
286 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
287 +
288 +static struct snd_soc_dai_link snd_allo_digione_dai[] = {
289 +{
290 +       .name        = "Allo DigiOne",
291 +       .stream_name = "Allo DigiOne HiFi",
292 +       SND_SOC_DAILINK_REG(allo_digione),
293 +},
294 +};
295 +
296 +static struct snd_rpi_wm8804_drvdata drvdata_allo_digione = {
297 +       .card_name = "snd_allo_digione",
298 +       .dai       = snd_allo_digione_dai,
299 +       .probe     = snd_allo_digione_probe,
300 +};
301 +
302 +SND_SOC_DAILINK_DEFS(hifiberry_digi,
303 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
304 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
305 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
306 +
307 +static struct snd_soc_dai_link snd_hifiberry_digi_dai[] = {
308 +{
309 +       .name        = "HifiBerry Digi",
310 +       .stream_name = "HifiBerry Digi HiFi",
311 +       SND_SOC_DAILINK_REG(hifiberry_digi),
312 +},
313 +};
314 +
315 +static int snd_hifiberry_digi_probe(struct platform_device *pdev)
316 +{
317 +       pr_debug("%s\n", __func__);
318 +
319 +       if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
320 +               return 0;
321 +
322 +       snd_hifiberry_digi_dai->name = "HiFiBerry Digi+ Pro";
323 +       snd_hifiberry_digi_dai->stream_name = "HiFiBerry Digi+ Pro HiFi";
324 +       return 0;
325 +}
326 +
327 +static struct snd_rpi_wm8804_drvdata drvdata_hifiberry_digi = {
328 +       .card_name = "snd_rpi_hifiberry_digi",
329 +       .dai       = snd_hifiberry_digi_dai,
330 +       .probe     = snd_hifiberry_digi_probe,
331 +};
332 +
333 +static const struct of_device_id snd_rpi_wm8804_of_match[] = {
334 +       { .compatible = "justboom,justboom-digi",
335 +               .data = (void *) &drvdata_justboom_digi },
336 +       { .compatible = "iqaudio,wm8804-digi",
337 +               .data = (void *) &drvdata_iqaudio_digi },
338 +       { .compatible = "allo,allo-digione",
339 +               .data = (void *) &drvdata_allo_digione },
340 +       { .compatible = "hifiberry,hifiberry-digi",
341 +               .data = (void *) &drvdata_hifiberry_digi },
342 +       {},
343 +};
344 +
345 +static struct snd_soc_card snd_rpi_wm8804 = {
346 +       .driver_name  = "RPi-WM8804",
347 +       .owner        = THIS_MODULE,
348 +       .dai_link     = NULL,
349 +       .num_links    = 1,
350 +};
351 +
352 +static int snd_rpi_wm8804_probe(struct platform_device *pdev)
353 +{
354 +       int ret = 0;
355 +       const struct of_device_id *of_id;
356 +
357 +       snd_rpi_wm8804.dev = &pdev->dev;
358 +       of_id = of_match_node(snd_rpi_wm8804_of_match, pdev->dev.of_node);
359 +
360 +       if (pdev->dev.of_node && of_id->data) {
361 +               struct device_node *i2s_node;
362 +               struct snd_rpi_wm8804_drvdata *drvdata =
363 +                       (struct snd_rpi_wm8804_drvdata *) of_id->data;
364 +               struct snd_soc_dai_link *dai = drvdata->dai;
365 +
366 +               snd_soc_card_set_drvdata(&snd_rpi_wm8804, drvdata);
367 +
368 +               if (!dai->ops)
369 +                       dai->ops = &snd_rpi_wm8804_ops;
370 +               if (!dai->codecs->dai_name)
371 +                       dai->codecs->dai_name = "wm8804-spdif";
372 +               if (!dai->codecs->name)
373 +                       dai->codecs->name = "wm8804.1-003b";
374 +               if (!dai->dai_fmt)
375 +                       dai->dai_fmt = SND_SOC_DAIFMT_I2S |
376 +                               SND_SOC_DAIFMT_NB_NF |
377 +                               SND_SOC_DAIFMT_CBM_CFM;
378 +
379 +               snd_rpi_wm8804.dai_link = dai;
380 +               i2s_node = of_parse_phandle(pdev->dev.of_node,
381 +                               "i2s-controller", 0);
382 +               if (!i2s_node) {
383 +                       pr_err("Failed to find i2s-controller DT node\n");
384 +                       return -ENODEV;
385 +               }
386 +
387 +               snd_rpi_wm8804.name = drvdata->card_name;
388 +
389 +               /* If requested by in drvdata get card & DAI names from DT */
390 +               if (drvdata->card_name_dt)
391 +                       of_property_read_string(i2s_node,
392 +                                       drvdata->card_name_dt,
393 +                                       &snd_rpi_wm8804.name);
394 +
395 +               if (drvdata->dai_name_dt)
396 +                       of_property_read_string(i2s_node,
397 +                                       drvdata->dai_name_dt,
398 +                                       &dai->name);
399 +
400 +               if (drvdata->dai_stream_name_dt)
401 +                       of_property_read_string(i2s_node,
402 +                                       drvdata->dai_stream_name_dt,
403 +                                       &dai->stream_name);
404 +
405 +               dai->cpus->of_node = i2s_node;
406 +               dai->platforms->of_node = i2s_node;
407 +
408 +               /*
409 +                * clk44gpio and clk48gpio are not required by all cards so
410 +                * don't check the error status.
411 +                */
412 +               snd_clk44gpio =
413 +                       devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW);
414 +
415 +               snd_clk48gpio =
416 +                       devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW);
417 +
418 +               if (drvdata->probe) {
419 +                       ret = drvdata->probe(pdev);
420 +                       if (ret < 0) {
421 +                               dev_err(&pdev->dev, "Custom probe failed %d\n",
422 +                                               ret);
423 +                               return ret;
424 +                       }
425 +               }
426 +
427 +               pr_debug("%s card: %s dai: %s stream: %s\n", __func__,
428 +                               snd_rpi_wm8804.name,
429 +                               dai->name, dai->stream_name);
430 +       }
431 +
432 +       ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_wm8804);
433 +       if (ret && ret != -EPROBE_DEFER)
434 +               dev_err(&pdev->dev, "Failed to register card %d\n", ret);
435 +
436 +       return ret;
437 +}
438 +
439 +static struct platform_driver snd_rpi_wm8804_driver = {
440 +       .driver = {
441 +               .name           = "snd-rpi-wm8804",
442 +               .owner          = THIS_MODULE,
443 +               .of_match_table = snd_rpi_wm8804_of_match,
444 +       },
445 +       .probe  = snd_rpi_wm8804_probe,
446 +};
447 +MODULE_DEVICE_TABLE(of, snd_rpi_wm8804_of_match);
448 +
449 +module_platform_driver(snd_rpi_wm8804_driver);
450 +
451 +MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
452 +MODULE_DESCRIPTION("ASoC Raspberry Pi Hat generic digi driver for WM8804 based cards");
453 +MODULE_LICENSE("GPL v2");
454 --- linux-5.15.orig/sound/soc/bcm/rpi-simple-soundcard.c        1970-01-01 01:00:00.000000000 +0100
455 +++ linux-5.15/sound/soc/bcm/rpi-simple-soundcard.c     2021-12-23 14:16:38.688758934 +0100
456 @@ -0,0 +1,419 @@
457 +// SPDX-License-Identifier: GPL-2.0
458 +/*
459 + * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard.
460 + *
461 + * Copyright (C) 2018 Raspberry Pi.
462 + *
463 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
464 + *
465 + * Based on code:
466 + * hifiberry_amp.c, hifiberry_dac.c, rpi-dac.c
467 + * by Florian Meier <florian.meier@koalo.de>
468 + *
469 + * googlevoicehat-soundcard.c
470 + * by Peter Malkin <petermalkin@google.com>
471 + *
472 + * adau1977-adc.c
473 + * by Andrey Grodzovsky <andrey2805@gmail.com>
474 + *
475 + * merus-amp.c
476 + * by Ariel Muszkat <ariel.muszkat@gmail.com>
477 + *             Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
478 + *
479 + * This program is free software; you can redistribute it and/or
480 + * modify it under the terms of the GNU General Public License
481 + * version 2 as published by the Free Software Foundation.
482 + *
483 + * This program is distributed in the hope that it will be useful, but
484 + * WITHOUT ANY WARRANTY; without even the implied warranty of
485 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
486 + * General Public License for more details.
487 + */
488 +
489 +#include <linux/module.h>
490 +#include <linux/platform_device.h>
491 +#include <linux/gpio/consumer.h>
492 +
493 +#include <sound/core.h>
494 +#include <sound/pcm.h>
495 +#include <sound/pcm_params.h>
496 +#include <sound/soc.h>
497 +
498 +/* Parameters for generic RPI functions */
499 +struct snd_rpi_simple_drvdata {
500 +       struct snd_soc_dai_link *dai;
501 +       const char* card_name;
502 +       unsigned int fixed_bclk_ratio;
503 +};
504 +
505 +static struct snd_soc_card snd_rpi_simple = {
506 +       .driver_name  = "RPi-simple",
507 +       .owner        = THIS_MODULE,
508 +       .dai_link     = NULL,
509 +       .num_links    = 1, /* Only a single DAI supported at the moment */
510 +};
511 +
512 +static int snd_rpi_simple_init(struct snd_soc_pcm_runtime *rtd)
513 +{
514 +       struct snd_rpi_simple_drvdata *drvdata =
515 +               snd_soc_card_get_drvdata(rtd->card);
516 +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
517 +
518 +       if (drvdata->fixed_bclk_ratio > 0)
519 +               return snd_soc_dai_set_bclk_ratio(cpu_dai,
520 +                               drvdata->fixed_bclk_ratio);
521 +
522 +       return 0;
523 +}
524 +
525 +static int pifi_mini_210_init(struct snd_soc_pcm_runtime *rtd)
526 +{
527 +       struct snd_soc_component *dac;
528 +       struct gpio_desc *pdn_gpio, *rst_gpio;
529 +       struct snd_soc_dai *codec_dai;
530 +       int ret;
531 +
532 +       snd_rpi_simple_init(rtd);
533 +       codec_dai = asoc_rtd_to_codec(rtd, 0);
534 +
535 +       dac = codec_dai[0].component;
536 +
537 +       pdn_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "pdn",
538 +                                               GPIOD_OUT_LOW);
539 +       if (IS_ERR(pdn_gpio)) {
540 +               ret = PTR_ERR(pdn_gpio);
541 +               dev_err(snd_rpi_simple.dev, "failed to get pdn gpio: %d\n", ret);
542 +               return ret;
543 +       }
544 +
545 +       rst_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "rst",
546 +                                               GPIOD_OUT_LOW);
547 +       if (IS_ERR(rst_gpio)) {
548 +               ret = PTR_ERR(rst_gpio);
549 +               dev_err(snd_rpi_simple.dev, "failed to get rst gpio: %d\n", ret);
550 +               return ret;
551 +       }
552 +
553 +       // Set up cards - pulse power down and reset first, then
554 +       // set up according to datasheet
555 +       gpiod_set_value_cansleep(pdn_gpio, 1);
556 +       gpiod_set_value_cansleep(rst_gpio, 1);
557 +       usleep_range(1000, 10000);
558 +       gpiod_set_value_cansleep(pdn_gpio, 0);
559 +       usleep_range(20000, 30000);
560 +       gpiod_set_value_cansleep(rst_gpio, 0);
561 +       usleep_range(20000, 30000);
562 +
563 +       // Oscillator trim
564 +       snd_soc_component_write(dac, 0x1b, 0);
565 +       usleep_range(60000, 80000);
566 +
567 +       // MCLK at 64fs, sample rate 44.1 or 48kHz
568 +       snd_soc_component_write(dac, 0x00, 0x60);
569 +
570 +       // Set up for BTL - AD/BD mode - AD is 0x00107772, BD is 0x00987772
571 +       snd_soc_component_write(dac, 0x20, 0x00107772);
572 +
573 +       // End mute
574 +       snd_soc_component_write(dac, 0x05, 0x00);
575 +
576 +       return 0;
577 +}
578 +
579 +static int snd_rpi_simple_hw_params(struct snd_pcm_substream *substream,
580 +               struct snd_pcm_hw_params *params)
581 +{
582 +       struct snd_soc_pcm_runtime *rtd = substream->private_data;
583 +       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
584 +       struct snd_rpi_simple_drvdata *drvdata;
585 +       unsigned int sample_bits;
586 +
587 +       drvdata = snd_soc_card_get_drvdata(rtd->card);
588 +
589 +       if (drvdata->fixed_bclk_ratio > 0)
590 +               return 0; // BCLK is configured in .init
591 +
592 +       /* The simple drivers just set the bclk_ratio to sample_bits * 2 so
593 +        * hard-code this for now. More complex drivers could just replace
594 +        * the hw_params routine.
595 +        */
596 +       sample_bits = snd_pcm_format_physical_width(params_format(params));
597 +       return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
598 +}
599 +
600 +static struct snd_soc_ops snd_rpi_simple_ops = {
601 +       .hw_params = snd_rpi_simple_hw_params,
602 +};
603 +
604 +enum adau1977_clk_id {
605 +       ADAU1977_SYSCLK,
606 +};
607 +
608 +enum adau1977_sysclk_src {
609 +       ADAU1977_SYSCLK_SRC_MCLK,
610 +       ADAU1977_SYSCLK_SRC_LRCLK,
611 +};
612 +
613 +static int adau1977_init(struct snd_soc_pcm_runtime *rtd)
614 +{
615 +       int ret;
616 +       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
617 +
618 +       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 0);
619 +       if (ret < 0)
620 +               return ret;
621 +
622 +       return snd_soc_component_set_sysclk(codec_dai->component,
623 +                       ADAU1977_SYSCLK, ADAU1977_SYSCLK_SRC_MCLK,
624 +                       11289600, SND_SOC_CLOCK_IN);
625 +}
626 +
627 +SND_SOC_DAILINK_DEFS(adau1977,
628 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
629 +       DAILINK_COMP_ARRAY(COMP_CODEC("adau1977.1-0011", "adau1977-hifi")),
630 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
631 +
632 +static struct snd_soc_dai_link snd_rpi_adau1977_dai[] = {
633 +       {
634 +       .name           = "adau1977",
635 +       .stream_name    = "ADAU1977",
636 +       .init           = adau1977_init,
637 +       .dai_fmt = SND_SOC_DAIFMT_I2S |
638 +               SND_SOC_DAIFMT_NB_NF |
639 +               SND_SOC_DAIFMT_CBM_CFM,
640 +       SND_SOC_DAILINK_REG(adau1977),
641 +       },
642 +};
643 +
644 +static struct snd_rpi_simple_drvdata drvdata_adau1977 = {
645 +       .card_name = "snd_rpi_adau1977_adc",
646 +       .dai       = snd_rpi_adau1977_dai,
647 +};
648 +
649 +SND_SOC_DAILINK_DEFS(gvchat,
650 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
651 +       DAILINK_COMP_ARRAY(COMP_CODEC("voicehat-codec", "voicehat-hifi")),
652 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
653 +
654 +static struct snd_soc_dai_link snd_googlevoicehat_soundcard_dai[] = {
655 +{
656 +       .name           = "Google voiceHAT SoundCard",
657 +       .stream_name    = "Google voiceHAT SoundCard HiFi",
658 +       .dai_fmt        =  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
659 +                               SND_SOC_DAIFMT_CBS_CFS,
660 +       SND_SOC_DAILINK_REG(gvchat),
661 +},
662 +};
663 +
664 +static struct snd_rpi_simple_drvdata drvdata_googlevoicehat = {
665 +       .card_name = "snd_rpi_googlevoicehat_soundcard",
666 +       .dai       = snd_googlevoicehat_soundcard_dai,
667 +};
668 +
669 +SND_SOC_DAILINK_DEFS(hifiberry_dacplusdsp,
670 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
671 +       DAILINK_COMP_ARRAY(COMP_CODEC("dacplusdsp-codec", "dacplusdsp-hifi")),
672 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
673 +
674 +static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
675 +{
676 +       .name           = "Hifiberry DAC+DSP SoundCard",
677 +       .stream_name    = "Hifiberry DAC+DSP SoundCard HiFi",
678 +       .dai_fmt        =  SND_SOC_DAIFMT_I2S |
679 +                          SND_SOC_DAIFMT_NB_NF |
680 +                          SND_SOC_DAIFMT_CBS_CFS,
681 +       SND_SOC_DAILINK_REG(hifiberry_dacplusdsp),
682 +},
683 +};
684 +
685 +static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
686 +       .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
687 +       .dai       = snd_hifiberrydacplusdsp_soundcard_dai,
688 +};
689 +
690 +SND_SOC_DAILINK_DEFS(hifiberry_amp,
691 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
692 +       DAILINK_COMP_ARRAY(COMP_CODEC("tas5713.1-001b", "tas5713-hifi")),
693 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
694 +
695 +static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
696 +       {
697 +               .name           = "HifiBerry AMP",
698 +               .stream_name    = "HifiBerry AMP HiFi",
699 +               .dai_fmt        = SND_SOC_DAIFMT_I2S |
700 +                                       SND_SOC_DAIFMT_NB_NF |
701 +                                       SND_SOC_DAIFMT_CBS_CFS,
702 +               SND_SOC_DAILINK_REG(hifiberry_amp),
703 +       },
704 +};
705 +
706 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_amp = {
707 +       .card_name        = "snd_rpi_hifiberry_amp",
708 +       .dai              = snd_hifiberry_amp_dai,
709 +       .fixed_bclk_ratio = 64,
710 +};
711 +
712 +SND_SOC_DAILINK_DEFS(hifiberry_dac,
713 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
714 +       DAILINK_COMP_ARRAY(COMP_CODEC("pcm5102a-codec", "pcm5102a-hifi")),
715 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
716 +
717 +static struct snd_soc_dai_link snd_hifiberry_dac_dai[] = {
718 +       {
719 +               .name           = "HifiBerry DAC",
720 +               .stream_name    = "HifiBerry DAC HiFi",
721 +               .dai_fmt        = SND_SOC_DAIFMT_I2S |
722 +                                       SND_SOC_DAIFMT_NB_NF |
723 +                                       SND_SOC_DAIFMT_CBS_CFS,
724 +               SND_SOC_DAILINK_REG(hifiberry_dac),
725 +       },
726 +};
727 +
728 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac = {
729 +       .card_name = "snd_rpi_hifiberry_dac",
730 +       .dai       = snd_hifiberry_dac_dai,
731 +};
732 +
733 +SND_SOC_DAILINK_DEFS(rpi_dac,
734 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
735 +       DAILINK_COMP_ARRAY(COMP_CODEC("pcm1794a-codec", "pcm1794a-hifi")),
736 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
737 +
738 +static struct snd_soc_dai_link snd_rpi_dac_dai[] = {
739 +{
740 +       .name           = "RPi-DAC",
741 +       .stream_name    = "RPi-DAC HiFi",
742 +       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
743 +                               SND_SOC_DAIFMT_CBS_CFS,
744 +       SND_SOC_DAILINK_REG(rpi_dac),
745 +},
746 +};
747 +
748 +static struct snd_rpi_simple_drvdata drvdata_rpi_dac = {
749 +       .card_name        = "snd_rpi_rpi_dac",
750 +       .dai              = snd_rpi_dac_dai,
751 +       .fixed_bclk_ratio = 64,
752 +};
753 +
754 +SND_SOC_DAILINK_DEFS(merus_amp,
755 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
756 +       DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p.1-0020","ma120x0p-amp")),
757 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
758 +
759 +static struct snd_soc_dai_link snd_merus_amp_dai[] = {
760 +       {
761 +               .name           = "MerusAmp",
762 +               .stream_name    = "Merus Audio Amp",
763 +               .dai_fmt        = SND_SOC_DAIFMT_I2S |
764 +                                       SND_SOC_DAIFMT_NB_NF |
765 +                                       SND_SOC_DAIFMT_CBS_CFS,
766 +               SND_SOC_DAILINK_REG(merus_amp),
767 +       },
768 +};
769 +
770 +static struct snd_rpi_simple_drvdata drvdata_merus_amp = {
771 +       .card_name        = "snd_rpi_merus_amp",
772 +       .dai              = snd_merus_amp_dai,
773 +       .fixed_bclk_ratio = 64,
774 +};
775 +
776 +SND_SOC_DAILINK_DEFS(pifi_mini_210,
777 +       DAILINK_COMP_ARRAY(COMP_EMPTY()),
778 +       DAILINK_COMP_ARRAY(COMP_CODEC("tas571x.1-001a", "tas571x-hifi")),
779 +       DAILINK_COMP_ARRAY(COMP_EMPTY()));
780 +
781 +static struct snd_soc_dai_link snd_pifi_mini_210_dai[] = {
782 +       {
783 +               .name           = "PiFi Mini 210",
784 +               .stream_name    = "PiFi Mini 210 HiFi",
785 +               .init                   = pifi_mini_210_init,
786 +               .dai_fmt        = SND_SOC_DAIFMT_I2S |
787 +                                       SND_SOC_DAIFMT_NB_NF |
788 +                                       SND_SOC_DAIFMT_CBS_CFS,
789 +               SND_SOC_DAILINK_REG(pifi_mini_210),
790 +       },
791 +};
792 +
793 +static struct snd_rpi_simple_drvdata drvdata_pifi_mini_210 = {
794 +       .card_name        = "snd_pifi_mini_210",
795 +       .dai              = snd_pifi_mini_210_dai,
796 +       .fixed_bclk_ratio = 64,
797 +};
798 +
799 +static const struct of_device_id snd_rpi_simple_of_match[] = {
800 +       { .compatible = "adi,adau1977-adc",
801 +               .data = (void *) &drvdata_adau1977 },
802 +       { .compatible = "googlevoicehat,googlevoicehat-soundcard",
803 +               .data = (void *) &drvdata_googlevoicehat },
804 +       { .compatible = "hifiberrydacplusdsp,hifiberrydacplusdsp-soundcard",
805 +               .data = (void *) &drvdata_hifiberrydacplusdsp },
806 +       { .compatible = "hifiberry,hifiberry-amp",
807 +               .data = (void *) &drvdata_hifiberry_amp },
808 +       { .compatible = "hifiberry,hifiberry-dac",
809 +               .data = (void *) &drvdata_hifiberry_dac },
810 +       { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac},
811 +       { .compatible = "merus,merus-amp",
812 +               .data = (void *) &drvdata_merus_amp },
813 +       { .compatible = "pifi,pifi-mini-210",
814 +               .data = (void *) &drvdata_pifi_mini_210 },
815 +       {},
816 +};
817 +
818 +static int snd_rpi_simple_probe(struct platform_device *pdev)
819 +{
820 +       int ret = 0;
821 +       const struct of_device_id *of_id;
822 +
823 +       snd_rpi_simple.dev = &pdev->dev;
824 +       of_id = of_match_node(snd_rpi_simple_of_match, pdev->dev.of_node);
825 +
826 +       if (pdev->dev.of_node && of_id->data) {
827 +               struct device_node *i2s_node;
828 +               struct snd_rpi_simple_drvdata *drvdata =
829 +                       (struct snd_rpi_simple_drvdata *) of_id->data;
830 +               struct snd_soc_dai_link *dai = drvdata->dai;
831 +
832 +               snd_soc_card_set_drvdata(&snd_rpi_simple, drvdata);
833 +
834 +               /* More complex drivers might override individual functions */
835 +               if (!dai->init)
836 +                       dai->init = snd_rpi_simple_init;
837 +               if (!dai->ops)
838 +                       dai->ops = &snd_rpi_simple_ops;
839 +
840 +               snd_rpi_simple.name = drvdata->card_name;
841 +
842 +               snd_rpi_simple.dai_link = dai;
843 +               i2s_node = of_parse_phandle(pdev->dev.of_node,
844 +                               "i2s-controller", 0);
845 +               if (!i2s_node) {
846 +                       pr_err("Failed to find i2s-controller DT node\n");
847 +                       return -ENODEV;
848 +               }
849 +
850 +               dai->cpus->of_node = i2s_node;
851 +               dai->platforms->of_node = i2s_node;
852 +       }
853 +
854 +       ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_simple);
855 +       if (ret && ret != -EPROBE_DEFER)
856 +               dev_err(&pdev->dev, "Failed to register card %d\n", ret);
857 +
858 +       return ret;
859 +}
860 +
861 +static struct platform_driver snd_rpi_simple_driver = {
862 +       .driver = {
863 +               .name   = "snd-rpi-simple",
864 +               .owner  = THIS_MODULE,
865 +               .of_match_table = snd_rpi_simple_of_match,
866 +       },
867 +       .probe          = snd_rpi_simple_probe,
868 +};
869 +MODULE_DEVICE_TABLE(of, snd_rpi_simple_of_match);
870 +
871 +module_platform_driver(snd_rpi_simple_driver);
872 +
873 +MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
874 +MODULE_DESCRIPTION("ASoC Raspberry Pi simple soundcard driver ");
875 +MODULE_LICENSE("GPL v2");
This page took 0.136621 seconds and 3 git commands to generate.