Merge tag 'v5.15.57' into rpi-5.15.y
[platform/kernel/linux-rpi.git] / sound / soc / bcm / rpi-proto.c
1 /*
2  * ASoC driver for PROTO AudioCODEC (with a WM8731)
3  * connected to a Raspberry Pi
4  *
5  * Author:      Florian Meier, <koalo@koalo.de>
6  *            Copyright 2013
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/soc.h>
19 #include <sound/jack.h>
20
21 #include "../codecs/wm8731.h"
22
23 static const unsigned int wm8731_rates_12288000[] = {
24         8000, 32000, 48000, 96000,
25 };
26
27 static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
28         .list = wm8731_rates_12288000,
29         .count = ARRAY_SIZE(wm8731_rates_12288000),
30 };
31
32 static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
33 {
34         /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
35         snd_pcm_hw_constraint_list(substream->runtime, 0,
36                                 SNDRV_PCM_HW_PARAM_RATE,
37                                 &wm8731_constraints_12288000);
38         return 0;
39 }
40
41 static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
42                                        struct snd_pcm_hw_params *params)
43 {
44         struct snd_soc_pcm_runtime *rtd = substream->private_data;
45         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
46         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
47         int sysclk = 12288000; /* This is fixed on this board */
48
49         /* Set proto bclk */
50         int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
51         if (ret < 0){
52                 dev_err(rtd->card->dev,
53                                 "Failed to set BCLK ratio %d\n", ret);
54                 return ret;
55         }
56
57         /* Set proto sysclk */
58         ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
59                         sysclk, SND_SOC_CLOCK_IN);
60         if (ret < 0) {
61                 dev_err(rtd->card->dev,
62                                 "Failed to set WM8731 SYSCLK: %d\n", ret);
63                 return ret;
64         }
65
66         return 0;
67 }
68
69 /* machine stream operations */
70 static struct snd_soc_ops snd_rpi_proto_ops = {
71         .startup = snd_rpi_proto_startup,
72         .hw_params = snd_rpi_proto_hw_params,
73 };
74
75 SND_SOC_DAILINK_DEFS(rpi_proto,
76         DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
77         DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.1-001a", "wm8731-hifi")),
78         DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
79
80 static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
81 {
82         .name           = "WM8731",
83         .stream_name    = "WM8731 HiFi",
84         .dai_fmt        = SND_SOC_DAIFMT_I2S
85                                 | SND_SOC_DAIFMT_NB_NF
86                                 | SND_SOC_DAIFMT_CBM_CFM,
87         .ops            = &snd_rpi_proto_ops,
88         SND_SOC_DAILINK_REG(rpi_proto),
89 },
90 };
91
92 /* audio machine driver */
93 static struct snd_soc_card snd_rpi_proto = {
94         .name           = "snd_rpi_proto",
95         .owner          = THIS_MODULE,
96         .dai_link       = snd_rpi_proto_dai,
97         .num_links      = ARRAY_SIZE(snd_rpi_proto_dai),
98 };
99
100 static int snd_rpi_proto_probe(struct platform_device *pdev)
101 {
102         int ret = 0;
103
104         snd_rpi_proto.dev = &pdev->dev;
105
106         if (pdev->dev.of_node) {
107                 struct device_node *i2s_node;
108                 struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
109                 i2s_node = of_parse_phandle(pdev->dev.of_node,
110                                             "i2s-controller", 0);
111
112                 if (i2s_node) {
113                         dai->cpus->dai_name = NULL;
114                         dai->cpus->of_node = i2s_node;
115                         dai->platforms->name = NULL;
116                         dai->platforms->of_node = i2s_node;
117                 }
118         }
119
120         ret = devm_snd_soc_register_card(&pdev->dev, &snd_rpi_proto);
121         if (ret && ret != -EPROBE_DEFER)
122                 dev_err(&pdev->dev,
123                                 "snd_soc_register_card() failed: %d\n", ret);
124
125         return ret;
126 }
127
128 static const struct of_device_id snd_rpi_proto_of_match[] = {
129         { .compatible = "rpi,rpi-proto", },
130         {},
131 };
132 MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
133
134 static struct platform_driver snd_rpi_proto_driver = {
135         .driver = {
136                 .name   = "snd-rpi-proto",
137                 .owner  = THIS_MODULE,
138                 .of_match_table = snd_rpi_proto_of_match,
139         },
140         .probe    = snd_rpi_proto_probe,
141 };
142
143 module_platform_driver(snd_rpi_proto_driver);
144
145 MODULE_AUTHOR("Florian Meier");
146 MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
147 MODULE_LICENSE("GPL");