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