1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <sound/core.h>
27#include <sound/soc.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc-dapm.h>
31#include <sound/jack.h>
32#include <linux/clk.h>
33#include <linux/gpio.h>
34#include <linux/module.h>
35#include <linux/i2c.h>
36#include <linux/acpi.h>
37
38#include "../codecs/da7219.h"
39#include "../codecs/da7219-aad.h"
40
41#define CZ_PLAT_CLK 24000000
42#define MCLK_RATE 24576000
43#define DUAL_CHANNEL 2
44
45static struct snd_soc_jack cz_jack;
46static struct clk *da7219_dai_clk;
47
48static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
49{
50 int ret;
51 struct snd_soc_card *card = rtd->card;
52 struct snd_soc_dai *codec_dai = rtd->codec_dai;
53 struct snd_soc_component *component = codec_dai->component;
54
55 dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
56
57 ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
58 CZ_PLAT_CLK, SND_SOC_CLOCK_IN);
59 if (ret < 0) {
60 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
61 return ret;
62 }
63
64 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
65 CZ_PLAT_CLK, MCLK_RATE);
66 if (ret < 0) {
67 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
68 return ret;
69 }
70
71 da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
72
73 ret = snd_soc_card_jack_new(card, "Headset Jack",
74 SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
75 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
76 SND_JACK_BTN_2 | SND_JACK_BTN_3,
77 &cz_jack, NULL, 0);
78 if (ret) {
79 dev_err(card->dev, "HP jack creation failed %d\n", ret);
80 return ret;
81 }
82
83 da7219_aad_jack_det(component, &cz_jack);
84
85 return 0;
86}
87
88static int cz_da7219_hw_params(struct snd_pcm_substream *substream,
89 struct snd_pcm_hw_params *params)
90{
91 int ret = 0;
92 struct snd_soc_pcm_runtime *rtd = substream->private_data;
93
94 ret = clk_prepare_enable(da7219_dai_clk);
95 if (ret < 0) {
96 dev_err(rtd->dev, "can't enable master clock %d\n", ret);
97 return ret;
98 }
99
100 return ret;
101}
102
103static int cz_da7219_hw_free(struct snd_pcm_substream *substream)
104{
105 clk_disable_unprepare(da7219_dai_clk);
106
107 return 0;
108}
109
110static const unsigned int channels[] = {
111 DUAL_CHANNEL,
112};
113
114static const unsigned int rates[] = {
115 48000,
116};
117
118static const struct snd_pcm_hw_constraint_list constraints_rates = {
119 .count = ARRAY_SIZE(rates),
120 .list = rates,
121 .mask = 0,
122};
123
124static const struct snd_pcm_hw_constraint_list constraints_channels = {
125 .count = ARRAY_SIZE(channels),
126 .list = channels,
127 .mask = 0,
128};
129
130static int cz_fe_startup(struct snd_pcm_substream *substream)
131{
132 struct snd_pcm_runtime *runtime = substream->runtime;
133
134
135
136
137
138 runtime->hw.channels_max = DUAL_CHANNEL;
139 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
140 &constraints_channels);
141 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
142 &constraints_rates);
143
144 return 0;
145}
146
147static struct snd_soc_ops cz_da7219_cap_ops = {
148 .hw_params = cz_da7219_hw_params,
149 .hw_free = cz_da7219_hw_free,
150 .startup = cz_fe_startup,
151};
152
153static struct snd_soc_ops cz_max_play_ops = {
154 .hw_params = cz_da7219_hw_params,
155 .hw_free = cz_da7219_hw_free,
156};
157
158static struct snd_soc_ops cz_dmic_cap_ops = {
159 .hw_params = cz_da7219_hw_params,
160 .hw_free = cz_da7219_hw_free,
161};
162
163static struct snd_soc_dai_link cz_dai_7219_98357[] = {
164 {
165 .name = "amd-da7219-play-cap",
166 .stream_name = "Playback and Capture",
167 .platform_name = "acp_audio_dma.0.auto",
168 .cpu_dai_name = "designware-i2s.3.auto",
169 .codec_dai_name = "da7219-hifi",
170 .codec_name = "i2c-DLGS7219:00",
171 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
172 | SND_SOC_DAIFMT_CBM_CFM,
173 .init = cz_da7219_init,
174 .dpcm_playback = 1,
175 .dpcm_capture = 1,
176 .ops = &cz_da7219_cap_ops,
177 },
178 {
179 .name = "amd-max98357-play",
180 .stream_name = "HiFi Playback",
181 .platform_name = "acp_audio_dma.0.auto",
182 .cpu_dai_name = "designware-i2s.1.auto",
183 .codec_dai_name = "HiFi",
184 .codec_name = "MX98357A:00",
185 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
186 | SND_SOC_DAIFMT_CBM_CFM,
187 .dpcm_playback = 1,
188 .ops = &cz_max_play_ops,
189 },
190 {
191 .name = "dmic",
192 .stream_name = "DMIC Capture",
193 .platform_name = "acp_audio_dma.0.auto",
194 .cpu_dai_name = "designware-i2s.2.auto",
195 .codec_dai_name = "adau7002-hifi",
196 .codec_name = "ADAU7002:00",
197 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
198 | SND_SOC_DAIFMT_CBM_CFM,
199 .dpcm_capture = 1,
200 .ops = &cz_dmic_cap_ops,
201 },
202};
203
204static const struct snd_soc_dapm_widget cz_widgets[] = {
205 SND_SOC_DAPM_HP("Headphones", NULL),
206 SND_SOC_DAPM_SPK("Speakers", NULL),
207 SND_SOC_DAPM_MIC("Headset Mic", NULL),
208 SND_SOC_DAPM_MIC("Int Mic", NULL),
209};
210
211static const struct snd_soc_dapm_route cz_audio_route[] = {
212 {"Headphones", NULL, "HPL"},
213 {"Headphones", NULL, "HPR"},
214 {"MIC", NULL, "Headset Mic"},
215 {"Speakers", NULL, "Speaker"},
216 {"PDM_DAT", NULL, "Int Mic"},
217};
218
219static const struct snd_kcontrol_new cz_mc_controls[] = {
220 SOC_DAPM_PIN_SWITCH("Headphones"),
221 SOC_DAPM_PIN_SWITCH("Speakers"),
222 SOC_DAPM_PIN_SWITCH("Headset Mic"),
223 SOC_DAPM_PIN_SWITCH("Int Mic"),
224};
225
226static struct snd_soc_card cz_card = {
227 .name = "acpd7219m98357",
228 .owner = THIS_MODULE,
229 .dai_link = cz_dai_7219_98357,
230 .num_links = ARRAY_SIZE(cz_dai_7219_98357),
231 .dapm_widgets = cz_widgets,
232 .num_dapm_widgets = ARRAY_SIZE(cz_widgets),
233 .dapm_routes = cz_audio_route,
234 .num_dapm_routes = ARRAY_SIZE(cz_audio_route),
235 .controls = cz_mc_controls,
236 .num_controls = ARRAY_SIZE(cz_mc_controls),
237};
238
239static int cz_probe(struct platform_device *pdev)
240{
241 int ret;
242 struct snd_soc_card *card;
243
244 card = &cz_card;
245 cz_card.dev = &pdev->dev;
246 platform_set_drvdata(pdev, card);
247 ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
248 if (ret) {
249 dev_err(&pdev->dev,
250 "devm_snd_soc_register_card(%s) failed: %d\n",
251 cz_card.name, ret);
252 return ret;
253 }
254 return 0;
255}
256
257static const struct acpi_device_id cz_audio_acpi_match[] = {
258 { "AMD7219", 0 },
259 {},
260};
261MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
262
263static struct platform_driver cz_pcm_driver = {
264 .driver = {
265 .name = "cz-da7219-max98357a",
266 .acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
267 .pm = &snd_soc_pm_ops,
268 },
269 .probe = cz_probe,
270};
271
272module_platform_driver(cz_pcm_driver);
273
274MODULE_AUTHOR("akshu.agrawal@amd.com");
275MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
276MODULE_LICENSE("GPL v2");
277