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
4 DSL/PON chips (bcm63158, bcm63178)
6 If you don't know what to do here, say N
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
14 + Say Y or M if you want to add support for HifiBerry DAC.
16 +config SND_RPI_SIMPLE_SOUNDCARD
17 + tristate "Support for Raspberry Pi simple soundcards"
19 + Say Y or M if you want to add support Raspbery Pi simple soundcards
21 +config SND_RPI_WM8804_SOUNDCARD
22 + tristate "Support for Raspberry Pi generic WM8804 soundcards"
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
29 # BCM63XX Platform Support
30 snd-soc-63xx-objs := bcm63xx-i2s-whistler.o bcm63xx-pcm-whistler.o
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
36 +snd-soc-rpi-simple-soundcard-objs := rpi-simple-soundcard.o
37 +snd-soc-rpi-wm8804-soundcard-objs := rpi-wm8804-soundcard.o
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
44 +// SPDX-License-Identifier: GPL-2.0
46 + * rpi--wm8804.c -- ALSA SoC Raspberry Pi soundcard.
48 + * Copyright (C) 2018 Raspberry Pi.
50 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
52 + * Generic driver for Pi Hat WM8804 digi sounds cards
54 + * Based upon code from:
56 + * by Milan Neskovic <info@justboom.co>
59 + * by Daniel Matuschek <info@crazy-audio.com>
62 + * by Baswaraj <jaikumar@cem-solutions.net>
65 + * Daniel Matuschek <info@crazy-audio.com>
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.
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.
77 +#include <linux/gpio/consumer.h>
78 +#include <linux/platform_device.h>
79 +#include <linux/module.h>
81 +#include <sound/core.h>
82 +#include <sound/pcm.h>
83 +#include <sound/pcm_params.h>
84 +#include <sound/soc.h>
86 +#include "../codecs/wm8804.h"
88 +struct wm8804_clk_cfg {
89 + unsigned int sysclk_freq;
90 + unsigned int mclk_freq;
91 + unsigned int mclk_div;
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);
108 +static struct gpio_desc *snd_clk44gpio;
109 +static struct gpio_desc *snd_clk48gpio;
110 +static int wm8804_samplerate = 0;
112 +/* Forward declarations */
113 +static struct snd_soc_dai_link snd_allo_digione_dai[];
114 +static struct snd_soc_card snd_rpi_wm8804;
117 +#define CLK_44EN_RATE 22579200UL
118 +#define CLK_48EN_RATE 24576000UL
120 +static unsigned int snd_rpi_wm8804_enable_clock(unsigned int samplerate)
122 + switch (samplerate) {
128 + gpiod_set_value_cansleep(snd_clk44gpio, 1);
129 + gpiod_set_value_cansleep(snd_clk48gpio, 0);
130 + return CLK_44EN_RATE;
132 + gpiod_set_value_cansleep(snd_clk48gpio, 1);
133 + gpiod_set_value_cansleep(snd_clk44gpio, 0);
134 + return CLK_48EN_RATE;
138 +static void snd_rpi_wm8804_clk_cfg(unsigned int samplerate,
139 + struct wm8804_clk_cfg *clk_cfg)
141 + clk_cfg->sysclk_freq = 27000000;
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;
148 + clk_cfg->mclk_freq = samplerate * 128;
149 + clk_cfg->mclk_div = WM8804_MCLKDIV_128FS;
152 + if (!(IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)))
153 + clk_cfg->sysclk_freq = snd_rpi_wm8804_enable_clock(samplerate);
156 +static int snd_rpi_wm8804_hw_params(struct snd_pcm_substream *substream,
157 + struct snd_pcm_hw_params *params)
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;
165 + struct wm8804_clk_cfg clk_cfg;
166 + int samplerate = params_rate(params);
168 + if (samplerate == wm8804_samplerate)
171 + /* clear until all clocks are setup properly */
172 + wm8804_samplerate = 0;
174 + snd_rpi_wm8804_clk_cfg(samplerate, &clk_cfg);
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);
180 + switch (samplerate) {
182 + sampling_freq = 0x03;
185 + sampling_freq = 0x00;
188 + sampling_freq = 0x02;
191 + sampling_freq = 0x08;
194 + sampling_freq = 0x0a;
197 + sampling_freq = 0x0c;
200 + sampling_freq = 0x0e;
203 + dev_err(rtd->card->dev,
204 + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
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);
212 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
213 + clk_cfg.sysclk_freq, SND_SOC_CLOCK_OUT);
215 + dev_err(rtd->card->dev,
216 + "Failed to set WM8804 SYSCLK: %d\n", ret);
220 + wm8804_samplerate = samplerate;
222 + /* set sampling frequency status bits */
223 + snd_soc_component_update_bits(component, WM8804_SPDTX4, 0x0f,
226 + return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
229 +static struct snd_soc_ops snd_rpi_wm8804_ops = {
230 + .hw_params = snd_rpi_wm8804_hw_params,
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()));
238 +static struct snd_soc_dai_link snd_justboom_digi_dai[] = {
240 + .name = "JustBoom Digi",
241 + .stream_name = "JustBoom Digi HiFi",
242 + SND_SOC_DAILINK_REG(justboom_digi),
246 +static struct snd_rpi_wm8804_drvdata drvdata_justboom_digi = {
247 + .card_name = "snd_rpi_justboom_digi",
248 + .dai = snd_justboom_digi_dai,
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()));
256 +static struct snd_soc_dai_link snd_iqaudio_digi_dai[] = {
258 + .name = "IQAudIO Digi",
259 + .stream_name = "IQAudIO Digi HiFi",
260 + SND_SOC_DAILINK_REG(iqaudio_digi),
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",
272 +static int snd_allo_digione_probe(struct platform_device *pdev)
274 + pr_debug("%s\n", __func__);
276 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio)) {
277 + dev_err(&pdev->dev, "devm_gpiod_get() failed\n");
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()));
288 +static struct snd_soc_dai_link snd_allo_digione_dai[] = {
290 + .name = "Allo DigiOne",
291 + .stream_name = "Allo DigiOne HiFi",
292 + SND_SOC_DAILINK_REG(allo_digione),
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,
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()));
307 +static struct snd_soc_dai_link snd_hifiberry_digi_dai[] = {
309 + .name = "HifiBerry Digi",
310 + .stream_name = "HifiBerry Digi HiFi",
311 + SND_SOC_DAILINK_REG(hifiberry_digi),
315 +static int snd_hifiberry_digi_probe(struct platform_device *pdev)
317 + pr_debug("%s\n", __func__);
319 + if (IS_ERR(snd_clk44gpio) || IS_ERR(snd_clk48gpio))
322 + snd_hifiberry_digi_dai->name = "HiFiBerry Digi+ Pro";
323 + snd_hifiberry_digi_dai->stream_name = "HiFiBerry Digi+ Pro HiFi";
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,
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 },
345 +static struct snd_soc_card snd_rpi_wm8804 = {
346 + .driver_name = "RPi-WM8804",
347 + .owner = THIS_MODULE,
352 +static int snd_rpi_wm8804_probe(struct platform_device *pdev)
355 + const struct of_device_id *of_id;
357 + snd_rpi_wm8804.dev = &pdev->dev;
358 + of_id = of_match_node(snd_rpi_wm8804_of_match, pdev->dev.of_node);
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;
366 + snd_soc_card_set_drvdata(&snd_rpi_wm8804, drvdata);
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";
375 + dai->dai_fmt = SND_SOC_DAIFMT_I2S |
376 + SND_SOC_DAIFMT_NB_NF |
377 + SND_SOC_DAIFMT_CBM_CFM;
379 + snd_rpi_wm8804.dai_link = dai;
380 + i2s_node = of_parse_phandle(pdev->dev.of_node,
381 + "i2s-controller", 0);
383 + pr_err("Failed to find i2s-controller DT node\n");
387 + snd_rpi_wm8804.name = drvdata->card_name;
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);
395 + if (drvdata->dai_name_dt)
396 + of_property_read_string(i2s_node,
397 + drvdata->dai_name_dt,
400 + if (drvdata->dai_stream_name_dt)
401 + of_property_read_string(i2s_node,
402 + drvdata->dai_stream_name_dt,
403 + &dai->stream_name);
405 + dai->cpus->of_node = i2s_node;
406 + dai->platforms->of_node = i2s_node;
409 + * clk44gpio and clk48gpio are not required by all cards so
410 + * don't check the error status.
413 + devm_gpiod_get(&pdev->dev, "clock44", GPIOD_OUT_LOW);
416 + devm_gpiod_get(&pdev->dev, "clock48", GPIOD_OUT_LOW);
418 + if (drvdata->probe) {
419 + ret = drvdata->probe(pdev);
421 + dev_err(&pdev->dev, "Custom probe failed %d\n",
427 + pr_debug("%s card: %s dai: %s stream: %s\n", __func__,
428 + snd_rpi_wm8804.name,
429 + dai->name, dai->stream_name);
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);
439 +static struct platform_driver snd_rpi_wm8804_driver = {
441 + .name = "snd-rpi-wm8804",
442 + .owner = THIS_MODULE,
443 + .of_match_table = snd_rpi_wm8804_of_match,
445 + .probe = snd_rpi_wm8804_probe,
447 +MODULE_DEVICE_TABLE(of, snd_rpi_wm8804_of_match);
449 +module_platform_driver(snd_rpi_wm8804_driver);
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
457 +// SPDX-License-Identifier: GPL-2.0
459 + * rpi-simple-soundcard.c -- ALSA SoC Raspberry Pi soundcard.
461 + * Copyright (C) 2018 Raspberry Pi.
463 + * Authors: Tim Gover <tim.gover@raspberrypi.org>
466 + * hifiberry_amp.c, hifiberry_dac.c, rpi-dac.c
467 + * by Florian Meier <florian.meier@koalo.de>
469 + * googlevoicehat-soundcard.c
470 + * by Peter Malkin <petermalkin@google.com>
473 + * by Andrey Grodzovsky <andrey2805@gmail.com>
476 + * by Ariel Muszkat <ariel.muszkat@gmail.com>
477 + * Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
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.
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.
489 +#include <linux/module.h>
490 +#include <linux/platform_device.h>
491 +#include <linux/gpio/consumer.h>
493 +#include <sound/core.h>
494 +#include <sound/pcm.h>
495 +#include <sound/pcm_params.h>
496 +#include <sound/soc.h>
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;
505 +static struct snd_soc_card snd_rpi_simple = {
506 + .driver_name = "RPi-simple",
507 + .owner = THIS_MODULE,
509 + .num_links = 1, /* Only a single DAI supported at the moment */
512 +static int snd_rpi_simple_init(struct snd_soc_pcm_runtime *rtd)
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);
518 + if (drvdata->fixed_bclk_ratio > 0)
519 + return snd_soc_dai_set_bclk_ratio(cpu_dai,
520 + drvdata->fixed_bclk_ratio);
525 +static int pifi_mini_210_init(struct snd_soc_pcm_runtime *rtd)
527 + struct snd_soc_component *dac;
528 + struct gpio_desc *pdn_gpio, *rst_gpio;
529 + struct snd_soc_dai *codec_dai;
532 + snd_rpi_simple_init(rtd);
533 + codec_dai = asoc_rtd_to_codec(rtd, 0);
535 + dac = codec_dai[0].component;
537 + pdn_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "pdn",
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);
545 + rst_gpio = devm_gpiod_get_optional(snd_rpi_simple.dev, "rst",
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);
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);
564 + snd_soc_component_write(dac, 0x1b, 0);
565 + usleep_range(60000, 80000);
567 + // MCLK at 64fs, sample rate 44.1 or 48kHz
568 + snd_soc_component_write(dac, 0x00, 0x60);
570 + // Set up for BTL - AD/BD mode - AD is 0x00107772, BD is 0x00987772
571 + snd_soc_component_write(dac, 0x20, 0x00107772);
574 + snd_soc_component_write(dac, 0x05, 0x00);
579 +static int snd_rpi_simple_hw_params(struct snd_pcm_substream *substream,
580 + struct snd_pcm_hw_params *params)
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;
587 + drvdata = snd_soc_card_get_drvdata(rtd->card);
589 + if (drvdata->fixed_bclk_ratio > 0)
590 + return 0; // BCLK is configured in .init
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.
596 + sample_bits = snd_pcm_format_physical_width(params_format(params));
597 + return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
600 +static struct snd_soc_ops snd_rpi_simple_ops = {
601 + .hw_params = snd_rpi_simple_hw_params,
604 +enum adau1977_clk_id {
608 +enum adau1977_sysclk_src {
609 + ADAU1977_SYSCLK_SRC_MCLK,
610 + ADAU1977_SYSCLK_SRC_LRCLK,
613 +static int adau1977_init(struct snd_soc_pcm_runtime *rtd)
616 + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
618 + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 0);
622 + return snd_soc_component_set_sysclk(codec_dai->component,
623 + ADAU1977_SYSCLK, ADAU1977_SYSCLK_SRC_MCLK,
624 + 11289600, SND_SOC_CLOCK_IN);
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()));
632 +static struct snd_soc_dai_link snd_rpi_adau1977_dai[] = {
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),
644 +static struct snd_rpi_simple_drvdata drvdata_adau1977 = {
645 + .card_name = "snd_rpi_adau1977_adc",
646 + .dai = snd_rpi_adau1977_dai,
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()));
654 +static struct snd_soc_dai_link snd_googlevoicehat_soundcard_dai[] = {
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),
664 +static struct snd_rpi_simple_drvdata drvdata_googlevoicehat = {
665 + .card_name = "snd_rpi_googlevoicehat_soundcard",
666 + .dai = snd_googlevoicehat_soundcard_dai,
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()));
674 +static struct snd_soc_dai_link snd_hifiberrydacplusdsp_soundcard_dai[] = {
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),
685 +static struct snd_rpi_simple_drvdata drvdata_hifiberrydacplusdsp = {
686 + .card_name = "snd_rpi_hifiberrydacplusdsp_soundcard",
687 + .dai = snd_hifiberrydacplusdsp_soundcard_dai,
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()));
695 +static struct snd_soc_dai_link snd_hifiberry_amp_dai[] = {
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),
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,
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()));
717 +static struct snd_soc_dai_link snd_hifiberry_dac_dai[] = {
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),
728 +static struct snd_rpi_simple_drvdata drvdata_hifiberry_dac = {
729 + .card_name = "snd_rpi_hifiberry_dac",
730 + .dai = snd_hifiberry_dac_dai,
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()));
738 +static struct snd_soc_dai_link snd_rpi_dac_dai[] = {
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),
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,
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()));
759 +static struct snd_soc_dai_link snd_merus_amp_dai[] = {
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),
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,
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()));
781 +static struct snd_soc_dai_link snd_pifi_mini_210_dai[] = {
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),
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,
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 },
818 +static int snd_rpi_simple_probe(struct platform_device *pdev)
821 + const struct of_device_id *of_id;
823 + snd_rpi_simple.dev = &pdev->dev;
824 + of_id = of_match_node(snd_rpi_simple_of_match, pdev->dev.of_node);
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;
832 + snd_soc_card_set_drvdata(&snd_rpi_simple, drvdata);
834 + /* More complex drivers might override individual functions */
836 + dai->init = snd_rpi_simple_init;
838 + dai->ops = &snd_rpi_simple_ops;
840 + snd_rpi_simple.name = drvdata->card_name;
842 + snd_rpi_simple.dai_link = dai;
843 + i2s_node = of_parse_phandle(pdev->dev.of_node,
844 + "i2s-controller", 0);
846 + pr_err("Failed to find i2s-controller DT node\n");
850 + dai->cpus->of_node = i2s_node;
851 + dai->platforms->of_node = i2s_node;
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);
861 +static struct platform_driver snd_rpi_simple_driver = {
863 + .name = "snd-rpi-simple",
864 + .owner = THIS_MODULE,
865 + .of_match_table = snd_rpi_simple_of_match,
867 + .probe = snd_rpi_simple_probe,
869 +MODULE_DEVICE_TABLE(of, snd_rpi_simple_of_match);
871 +module_platform_driver(snd_rpi_simple_driver);
873 +MODULE_AUTHOR("Tim Gover <tim.gover@raspberrypi.org>");
874 +MODULE_DESCRIPTION("ASoC Raspberry Pi simple soundcard driver ");
875 +MODULE_LICENSE("GPL v2");