ASoC: AMD: Configure channel 1 or channel 0 for capture
[sfrench/cifs-2.6.git] / sound / soc / amd / acp-da7219-max98357a.c
1 /*
2  * Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec
3  *
4  * Copyright 2017 Advanced Micro Devices, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
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/input.h>
37 #include <linux/acpi.h>
38
39 #include "acp.h"
40 #include "../codecs/da7219.h"
41 #include "../codecs/da7219-aad.h"
42
43 #define CZ_PLAT_CLK 25000000
44 #define DUAL_CHANNEL            2
45
46 static struct snd_soc_jack cz_jack;
47 static struct clk *da7219_dai_clk;
48 extern int bt_uart_enable;
49
50 static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
51 {
52         int ret;
53         struct snd_soc_card *card = rtd->card;
54         struct snd_soc_dai *codec_dai = rtd->codec_dai;
55         struct snd_soc_component *component = codec_dai->component;
56
57         dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);
58
59         ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK,
60                                      CZ_PLAT_CLK, SND_SOC_CLOCK_IN);
61         if (ret < 0) {
62                 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
63                 return ret;
64         }
65
66         ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL,
67                                   CZ_PLAT_CLK, DA7219_PLL_FREQ_OUT_98304);
68         if (ret < 0) {
69                 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
70                 return ret;
71         }
72
73         da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
74
75         ret = snd_soc_card_jack_new(card, "Headset Jack",
76                                 SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
77                                 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
78                                 SND_JACK_BTN_2 | SND_JACK_BTN_3,
79                                 &cz_jack, NULL, 0);
80         if (ret) {
81                 dev_err(card->dev, "HP jack creation failed %d\n", ret);
82                 return ret;
83         }
84
85         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
86         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
87         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
88         snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
89
90         da7219_aad_jack_det(component, &cz_jack);
91
92         return 0;
93 }
94
95 static int da7219_clk_enable(struct snd_pcm_substream *substream)
96 {
97         int ret = 0;
98         struct snd_soc_pcm_runtime *rtd = substream->private_data;
99
100         ret = clk_prepare_enable(da7219_dai_clk);
101         if (ret < 0) {
102                 dev_err(rtd->dev, "can't enable master clock %d\n", ret);
103                 return ret;
104         }
105
106         return ret;
107 }
108
109 static void da7219_clk_disable(void)
110 {
111         clk_disable_unprepare(da7219_dai_clk);
112 }
113
114 static const unsigned int channels[] = {
115         DUAL_CHANNEL,
116 };
117
118 static const unsigned int rates[] = {
119         48000,
120 };
121
122 static const struct snd_pcm_hw_constraint_list constraints_rates = {
123         .count = ARRAY_SIZE(rates),
124         .list  = rates,
125         .mask = 0,
126 };
127
128 static const struct snd_pcm_hw_constraint_list constraints_channels = {
129         .count = ARRAY_SIZE(channels),
130         .list = channels,
131         .mask = 0,
132 };
133
134 static int cz_da7219_startup(struct snd_pcm_substream *substream)
135 {
136         struct snd_pcm_runtime *runtime = substream->runtime;
137         struct snd_soc_pcm_runtime *rtd = substream->private_data;
138         struct snd_soc_card *card = rtd->card;
139         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
140
141         /*
142          * On this platform for PCM device we support stereo
143          */
144
145         runtime->hw.channels_max = DUAL_CHANNEL;
146         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
147                                    &constraints_channels);
148         snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
149                                    &constraints_rates);
150
151         machine->i2s_instance = I2S_SP_INSTANCE;
152         machine->capture_channel = CAP_CHANNEL1;
153         return da7219_clk_enable(substream);
154 }
155
156 static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
157 {
158         da7219_clk_disable();
159 }
160
161 static int cz_max_startup(struct snd_pcm_substream *substream)
162 {
163         struct snd_soc_pcm_runtime *rtd = substream->private_data;
164         struct snd_soc_card *card = rtd->card;
165         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
166
167         machine->i2s_instance = I2S_BT_INSTANCE;
168         return da7219_clk_enable(substream);
169 }
170
171 static void cz_max_shutdown(struct snd_pcm_substream *substream)
172 {
173         da7219_clk_disable();
174 }
175
176 static int cz_dmic0_startup(struct snd_pcm_substream *substream)
177 {
178         struct snd_soc_pcm_runtime *rtd = substream->private_data;
179         struct snd_soc_card *card = rtd->card;
180         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
181
182         machine->i2s_instance = I2S_BT_INSTANCE;
183         return da7219_clk_enable(substream);
184 }
185
186 static int cz_dmic1_startup(struct snd_pcm_substream *substream)
187 {
188         struct snd_soc_pcm_runtime *rtd = substream->private_data;
189         struct snd_soc_card *card = rtd->card;
190         struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
191
192         machine->i2s_instance = I2S_SP_INSTANCE;
193         machine->capture_channel = CAP_CHANNEL0;
194         return da7219_clk_enable(substream);
195 }
196
197 static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
198 {
199         da7219_clk_disable();
200 }
201
202 static const struct snd_soc_ops cz_da7219_cap_ops = {
203         .startup = cz_da7219_startup,
204         .shutdown = cz_da7219_shutdown,
205 };
206
207 static const struct snd_soc_ops cz_max_play_ops = {
208         .startup = cz_max_startup,
209         .shutdown = cz_max_shutdown,
210 };
211
212 static const struct snd_soc_ops cz_dmic0_cap_ops = {
213         .startup = cz_dmic0_startup,
214         .shutdown = cz_dmic_shutdown,
215 };
216
217 static const struct snd_soc_ops cz_dmic1_cap_ops = {
218         .startup = cz_dmic1_startup,
219         .shutdown = cz_dmic_shutdown,
220 };
221
222 static struct snd_soc_dai_link cz_dai_7219_98357[] = {
223         {
224                 .name = "amd-da7219-play",
225                 .stream_name = "Playback",
226                 .platform_name = "acp_audio_dma.0.auto",
227                 .cpu_dai_name = "designware-i2s.1.auto",
228                 .codec_dai_name = "da7219-hifi",
229                 .codec_name = "i2c-DLGS7219:00",
230                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
231                                 | SND_SOC_DAIFMT_CBM_CFM,
232                 .init = cz_da7219_init,
233                 .dpcm_playback = 1,
234                 .ops = &cz_da7219_cap_ops,
235         },
236         {
237                 .name = "amd-da7219-cap",
238                 .stream_name = "Capture",
239                 .platform_name = "acp_audio_dma.0.auto",
240                 .cpu_dai_name = "designware-i2s.2.auto",
241                 .codec_dai_name = "da7219-hifi",
242                 .codec_name = "i2c-DLGS7219:00",
243                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
244                                 | SND_SOC_DAIFMT_CBM_CFM,
245                 .dpcm_capture = 1,
246                 .ops = &cz_da7219_cap_ops,
247         },
248         {
249                 .name = "amd-max98357-play",
250                 .stream_name = "HiFi Playback",
251                 .platform_name = "acp_audio_dma.0.auto",
252                 .cpu_dai_name = "designware-i2s.3.auto",
253                 .codec_dai_name = "HiFi",
254                 .codec_name = "MX98357A:00",
255                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
256                                 | SND_SOC_DAIFMT_CBM_CFM,
257                 .dpcm_playback = 1,
258                 .ops = &cz_max_play_ops,
259         },
260         {
261                 /* C panel DMIC */
262                 .name = "dmic0",
263                 .stream_name = "DMIC0 Capture",
264                 .platform_name = "acp_audio_dma.0.auto",
265                 .cpu_dai_name = "designware-i2s.3.auto",
266                 .codec_dai_name = "adau7002-hifi",
267                 .codec_name = "ADAU7002:00",
268                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
269                                 | SND_SOC_DAIFMT_CBM_CFM,
270                 .dpcm_capture = 1,
271                 .ops = &cz_dmic0_cap_ops,
272         },
273         {
274                 /* A/B panel DMIC */
275                 .name = "dmic1",
276                 .stream_name = "DMIC1 Capture",
277                 .platform_name = "acp_audio_dma.0.auto",
278                 .cpu_dai_name = "designware-i2s.2.auto",
279                 .codec_dai_name = "adau7002-hifi",
280                 .codec_name = "ADAU7002:00",
281                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
282                                 | SND_SOC_DAIFMT_CBM_CFM,
283                 .dpcm_capture = 1,
284                 .ops = &cz_dmic1_cap_ops,
285         },
286 };
287
288 static const struct snd_soc_dapm_widget cz_widgets[] = {
289         SND_SOC_DAPM_HP("Headphones", NULL),
290         SND_SOC_DAPM_SPK("Speakers", NULL),
291         SND_SOC_DAPM_MIC("Headset Mic", NULL),
292         SND_SOC_DAPM_MIC("Int Mic", NULL),
293 };
294
295 static const struct snd_soc_dapm_route cz_audio_route[] = {
296         {"Headphones", NULL, "HPL"},
297         {"Headphones", NULL, "HPR"},
298         {"MIC", NULL, "Headset Mic"},
299         {"Speakers", NULL, "Speaker"},
300         {"PDM_DAT", NULL, "Int Mic"},
301 };
302
303 static const struct snd_kcontrol_new cz_mc_controls[] = {
304         SOC_DAPM_PIN_SWITCH("Headphones"),
305         SOC_DAPM_PIN_SWITCH("Speakers"),
306         SOC_DAPM_PIN_SWITCH("Headset Mic"),
307         SOC_DAPM_PIN_SWITCH("Int Mic"),
308 };
309
310 static struct snd_soc_card cz_card = {
311         .name = "acpd7219m98357",
312         .owner = THIS_MODULE,
313         .dai_link = cz_dai_7219_98357,
314         .num_links = ARRAY_SIZE(cz_dai_7219_98357),
315         .dapm_widgets = cz_widgets,
316         .num_dapm_widgets = ARRAY_SIZE(cz_widgets),
317         .dapm_routes = cz_audio_route,
318         .num_dapm_routes = ARRAY_SIZE(cz_audio_route),
319         .controls = cz_mc_controls,
320         .num_controls = ARRAY_SIZE(cz_mc_controls),
321 };
322
323 static int cz_probe(struct platform_device *pdev)
324 {
325         int ret;
326         struct snd_soc_card *card;
327         struct acp_platform_info *machine;
328
329         machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
330                                GFP_KERNEL);
331         if (!machine)
332                 return -ENOMEM;
333         card = &cz_card;
334         cz_card.dev = &pdev->dev;
335         platform_set_drvdata(pdev, card);
336         snd_soc_card_set_drvdata(card, machine);
337         ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
338         if (ret) {
339                 dev_err(&pdev->dev,
340                                 "devm_snd_soc_register_card(%s) failed: %d\n",
341                                 cz_card.name, ret);
342                 return ret;
343         }
344         bt_uart_enable = !device_property_read_bool(&pdev->dev,
345                                                     "bt-pad-enable");
346         return 0;
347 }
348
349 static const struct acpi_device_id cz_audio_acpi_match[] = {
350         { "AMD7219", 0 },
351         {},
352 };
353 MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
354
355 static struct platform_driver cz_pcm_driver = {
356         .driver = {
357                 .name = "cz-da7219-max98357a",
358                 .acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
359                 .pm = &snd_soc_pm_ops,
360         },
361         .probe = cz_probe,
362 };
363
364 module_platform_driver(cz_pcm_driver);
365
366 MODULE_AUTHOR("akshu.agrawal@amd.com");
367 MODULE_DESCRIPTION("DA7219 & MAX98357A audio support");
368 MODULE_LICENSE("GPL v2");