xref: /openbmc/linux/sound/soc/intel/boards/bxt_rt298.c (revision 4f205687)
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 		.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 		.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 		.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 		.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 		.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");
354