ASoC: Intel: Add Broxton-P machine driver
[sfrench/cifs-2.6.git] / sound / soc / intel / boards / bxt_rt298.c
1 /*
2  * Intel Broxton-P I2S Machine Driver
3  *
4  * Copyright (C) 2014-2016, Intel Corporation. All rights reserved.
5  *
6  * Modified from:
7  *   Intel Skylake I2S Machine driver
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License version
11  * 2 as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <sound/core.h>
22 #include <sound/pcm.h>
23 #include <sound/soc.h>
24 #include <sound/jack.h>
25 #include <sound/pcm_params.h>
26 #include "../../codecs/hdac_hdmi.h"
27 #include "../../codecs/rt298.h"
28
29 static struct snd_soc_jack broxton_headset;
30 /* Headset jack detection DAPM pins */
31
32 enum {
33         BXT_DPCM_AUDIO_PB = 0,
34         BXT_DPCM_AUDIO_CP,
35         BXT_DPCM_AUDIO_REF_CP,
36         BXT_DPCM_AUDIO_HDMI1_PB,
37         BXT_DPCM_AUDIO_HDMI2_PB,
38         BXT_DPCM_AUDIO_HDMI3_PB,
39 };
40
41 static struct snd_soc_jack_pin broxton_headset_pins[] = {
42         {
43                 .pin = "Mic Jack",
44                 .mask = SND_JACK_MICROPHONE,
45         },
46         {
47                 .pin = "Headphone Jack",
48                 .mask = SND_JACK_HEADPHONE,
49         },
50 };
51
52 static const struct snd_kcontrol_new broxton_controls[] = {
53         SOC_DAPM_PIN_SWITCH("Speaker"),
54         SOC_DAPM_PIN_SWITCH("Headphone Jack"),
55         SOC_DAPM_PIN_SWITCH("Mic Jack"),
56 };
57
58 static const struct snd_soc_dapm_widget broxton_widgets[] = {
59         SND_SOC_DAPM_HP("Headphone Jack", NULL),
60         SND_SOC_DAPM_SPK("Speaker", NULL),
61         SND_SOC_DAPM_MIC("Mic Jack", NULL),
62         SND_SOC_DAPM_MIC("DMIC2", NULL),
63         SND_SOC_DAPM_MIC("SoC DMIC", NULL),
64         SND_SOC_DAPM_SPK("HDMI1", NULL),
65         SND_SOC_DAPM_SPK("HDMI2", NULL),
66         SND_SOC_DAPM_SPK("HDMI3", NULL),
67 };
68
69 static const struct snd_soc_dapm_route broxton_rt298_map[] = {
70         /* speaker */
71         {"Speaker", NULL, "SPOR"},
72         {"Speaker", NULL, "SPOL"},
73
74         /* HP jack connectors - unknown if we have jack detect */
75         {"Headphone Jack", NULL, "HPO Pin"},
76
77         /* other jacks */
78         {"MIC1", NULL, "Mic Jack"},
79
80         /* digital mics */
81         {"DMIC1 Pin", NULL, "DMIC2"},
82         {"DMic", NULL, "SoC DMIC"},
83
84         {"HDMI1", NULL, "hif5 Output"},
85         {"HDMI2", NULL, "hif6 Output"},
86         {"HDMI3", NULL, "hif7 Output"},
87
88         /* CODEC BE connections */
89         { "AIF1 Playback", NULL, "ssp5 Tx"},
90         { "ssp5 Tx", NULL, "codec0_out"},
91
92         { "codec0_in", NULL, "ssp5 Rx" },
93         { "ssp5 Rx", NULL, "AIF1 Capture" },
94
95         { "dmic01_hifi", NULL, "DMIC01 Rx" },
96         { "DMIC01 Rx", NULL, "Capture" },
97
98         { "hifi3", NULL, "iDisp3 Tx"},
99         { "iDisp3 Tx", NULL, "iDisp3_out"},
100         { "hifi2", NULL, "iDisp2 Tx"},
101         { "iDisp2 Tx", NULL, "iDisp2_out"},
102         { "hifi1", NULL, "iDisp1 Tx"},
103         { "iDisp1 Tx", NULL, "iDisp1_out"},
104
105 };
106
107 static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
108 {
109         struct snd_soc_codec *codec = rtd->codec;
110         int ret = 0;
111
112         ret = snd_soc_card_jack_new(rtd->card, "Headset",
113                 SND_JACK_HEADSET | SND_JACK_BTN_0,
114                 &broxton_headset,
115                 broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins));
116
117         if (ret)
118                 return ret;
119
120         rt298_mic_detect(codec, &broxton_headset);
121         return 0;
122 }
123
124 static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
125 {
126         struct snd_soc_dai *dai = rtd->codec_dai;
127
128         return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
129 }
130
131 static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
132                         struct snd_pcm_hw_params *params)
133 {
134         struct snd_interval *rate = hw_param_interval(params,
135                                         SNDRV_PCM_HW_PARAM_RATE);
136         struct snd_interval *channels = hw_param_interval(params,
137                                         SNDRV_PCM_HW_PARAM_CHANNELS);
138         struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
139
140         /* The ADSP will covert the FE rate to 48k, stereo */
141         rate->min = rate->max = 48000;
142         channels->min = channels->max = 2;
143
144         /* set SSP5 to 24 bit */
145         snd_mask_none(fmt);
146         snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
147
148         return 0;
149 }
150
151 static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,
152         struct snd_pcm_hw_params *params)
153 {
154         struct snd_soc_pcm_runtime *rtd = substream->private_data;
155         struct snd_soc_dai *codec_dai = rtd->codec_dai;
156         int ret;
157
158         ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL,
159                                         19200000, SND_SOC_CLOCK_IN);
160         if (ret < 0) {
161                 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
162                 return ret;
163         }
164
165         return ret;
166 }
167
168 static struct snd_soc_ops broxton_rt298_ops = {
169         .hw_params = broxton_rt298_hw_params,
170 };
171
172 /* broxton digital audio interface glue - connects codec <--> CPU */
173 static struct snd_soc_dai_link broxton_rt298_dais[] = {
174         /* Front End DAI links */
175         [BXT_DPCM_AUDIO_PB]
176         {
177                 .name = "Bxt Audio Port",
178                 .stream_name = "Audio",
179                 .cpu_dai_name = "System Pin",
180                 .platform_name = "0000:00:0e.0",
181                 .nonatomic = 1,
182                 .dynamic = 1,
183                 .codec_name = "snd-soc-dummy",
184                 .codec_dai_name = "snd-soc-dummy-dai",
185                 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
186                 .dpcm_playback = 1,
187         },
188         [BXT_DPCM_AUDIO_CP]
189         {
190                 .name = "Bxt Audio Capture Port",
191                 .stream_name = "Audio Record",
192                 .cpu_dai_name = "System Pin",
193                 .platform_name = "0000:00:0e.0",
194                 .nonatomic = 1,
195                 .dynamic = 1,
196                 .codec_name = "snd-soc-dummy",
197                 .codec_dai_name = "snd-soc-dummy-dai",
198                 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
199                 .dpcm_capture = 1,
200         },
201         [BXT_DPCM_AUDIO_REF_CP]
202         {
203                 .name = "Bxt Audio Reference cap",
204                 .stream_name = "refcap",
205                 .cpu_dai_name = "Reference Pin",
206                 .codec_name = "snd-soc-dummy",
207                 .codec_dai_name = "snd-soc-dummy-dai",
208                 .platform_name = "0000:00:0e.0",
209                 .init = NULL,
210                 .dpcm_capture = 1,
211                 .nonatomic = 1,
212                 .dynamic = 1,
213         },
214         [BXT_DPCM_AUDIO_HDMI1_PB]
215         {
216                 .name = "Bxt HDMI Port1",
217                 .stream_name = "Hdmi1",
218                 .cpu_dai_name = "HDMI1 Pin",
219                 .codec_name = "snd-soc-dummy",
220                 .codec_dai_name = "snd-soc-dummy-dai",
221                 .platform_name = "0000:00:0e.0",
222                 .dpcm_playback = 1,
223                 .init = NULL,
224                 .nonatomic = 1,
225                 .dynamic = 1,
226         },
227         [BXT_DPCM_AUDIO_HDMI2_PB]
228         {
229                 .name = "Bxt HDMI Port2",
230                 .stream_name = "Hdmi2",
231                 .cpu_dai_name = "HDMI2 Pin",
232                 .codec_name = "snd-soc-dummy",
233                 .codec_dai_name = "snd-soc-dummy-dai",
234                 .platform_name = "0000:00:0e.0",
235                 .dpcm_playback = 1,
236                 .init = NULL,
237                 .nonatomic = 1,
238                 .dynamic = 1,
239         },
240         [BXT_DPCM_AUDIO_HDMI3_PB]
241         {
242                 .name = "Bxt HDMI Port3",
243                 .stream_name = "Hdmi3",
244                 .cpu_dai_name = "HDMI3 Pin",
245                 .codec_name = "snd-soc-dummy",
246                 .codec_dai_name = "snd-soc-dummy-dai",
247                 .platform_name = "0000:00:0e.0",
248                 .dpcm_playback = 1,
249                 .init = NULL,
250                 .nonatomic = 1,
251                 .dynamic = 1,
252         },
253         /* Back End DAI links */
254         {
255                 /* SSP5 - Codec */
256                 .name = "SSP5-Codec",
257                 .be_id = 0,
258                 .cpu_dai_name = "SSP5 Pin",
259                 .platform_name = "0000:00:0e.0",
260                 .no_pcm = 1,
261                 .codec_name = "i2c-INT343A:00",
262                 .codec_dai_name = "rt298-aif1",
263                 .init = broxton_rt298_codec_init,
264                 .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
265                                                 SND_SOC_DAIFMT_CBS_CFS,
266                 .ignore_pmdown_time = 1,
267                 .be_hw_params_fixup = broxton_ssp5_fixup,
268                 .ops = &broxton_rt298_ops,
269                 .dpcm_playback = 1,
270                 .dpcm_capture = 1,
271         },
272         {
273                 .name = "dmic01",
274                 .be_id = 1,
275                 .cpu_dai_name = "DMIC01 Pin",
276                 .codec_name = "dmic-codec",
277                 .codec_dai_name = "dmic-hifi",
278                 .platform_name = "0000:00:0e.0",
279                 .ignore_suspend = 1,
280                 .dpcm_capture = 1,
281                 .no_pcm = 1,
282         },
283         {
284                 .name = "iDisp1",
285                 .be_id = 3,
286                 .cpu_dai_name = "iDisp1 Pin",
287                 .codec_name = "ehdaudio0D2",
288                 .codec_dai_name = "intel-hdmi-hifi1",
289                 .platform_name = "0000:00:0e.0",
290                 .init = broxton_hdmi_init,
291                 .dpcm_playback = 1,
292                 .no_pcm = 1,
293         },
294         {
295                 .name = "iDisp2",
296                 .be_id = 4,
297                 .cpu_dai_name = "iDisp2 Pin",
298                 .codec_name = "ehdaudio0D2",
299                 .codec_dai_name = "intel-hdmi-hifi2",
300                 .platform_name = "0000:00:0e.0",
301                 .init = broxton_hdmi_init,
302                 .dpcm_playback = 1,
303                 .no_pcm = 1,
304         },
305         {
306                 .name = "iDisp3",
307                 .be_id = 5,
308                 .cpu_dai_name = "iDisp3 Pin",
309                 .codec_name = "ehdaudio0D2",
310                 .codec_dai_name = "intel-hdmi-hifi3",
311                 .platform_name = "0000:00:0e.0",
312                 .init = broxton_hdmi_init,
313                 .dpcm_playback = 1,
314                 .no_pcm = 1,
315         },
316 };
317
318 /* broxton audio machine driver for SPT + RT298S */
319 static struct snd_soc_card broxton_rt298 = {
320         .name = "broxton-rt298",
321         .owner = THIS_MODULE,
322         .dai_link = broxton_rt298_dais,
323         .num_links = ARRAY_SIZE(broxton_rt298_dais),
324         .controls = broxton_controls,
325         .num_controls = ARRAY_SIZE(broxton_controls),
326         .dapm_widgets = broxton_widgets,
327         .num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
328         .dapm_routes = broxton_rt298_map,
329         .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
330         .fully_routed = true,
331 };
332
333 static int broxton_audio_probe(struct platform_device *pdev)
334 {
335         broxton_rt298.dev = &pdev->dev;
336
337         return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
338 }
339
340 static struct platform_driver broxton_audio = {
341         .probe = broxton_audio_probe,
342         .driver = {
343                 .name = "bxt_alc298s_i2s",
344         },
345 };
346 module_platform_driver(broxton_audio)
347
348 /* Module information */
349 MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>");
350 MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
351 MODULE_DESCRIPTION("Intel SST Audio for Broxton");
352 MODULE_LICENSE("GPL v2");
353 MODULE_ALIAS("platform:bxt_alc298s_i2s");