blob: ab7da9c304b2049ceec9c06eb53ce25e1a809382 [file] [log] [blame]
Rohit Ainapure8eaf2b32015-12-11 11:29:08 -08001/*
2 * Intel Skylake I2S Machine Driver with MAXIM98357A
3 * and NAU88L25
4 *
5 * Copyright (C) 2015, Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <sound/core.h>
20#include <sound/jack.h>
21#include <sound/pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/soc.h>
24#include "../../codecs/nau8825.h"
25
26#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
27#define SKL_MAXIM_CODEC_DAI "HiFi"
28
29static struct snd_soc_jack skylake_headset;
30static struct snd_soc_card skylake_audio_card;
31
32static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
33{
34 struct snd_soc_pcm_runtime *rtd;
35
36 list_for_each_entry(rtd, &card->rtd_list, list) {
37
38 if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI,
39 strlen(SKL_NUVOTON_CODEC_DAI)))
40 return rtd->codec_dai;
41 }
42
43 return NULL;
44}
45
46static int platform_clock_control(struct snd_soc_dapm_widget *w,
47 struct snd_kcontrol *k, int event)
48{
49 struct snd_soc_dapm_context *dapm = w->dapm;
50 struct snd_soc_card *card = dapm->card;
51 struct snd_soc_dai *codec_dai;
52 int ret;
53
54 codec_dai = skl_get_codec_dai(card);
55 if (!codec_dai) {
56 dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
57 return -EIO;
58 }
59
60 if (SND_SOC_DAPM_EVENT_ON(event)) {
61 ret = snd_soc_dai_set_sysclk(codec_dai,
62 NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
63 if (ret < 0) {
64 dev_err(card->dev, "set sysclk err = %d\n", ret);
65 return -EIO;
66 }
67 } else {
68 ret = snd_soc_dai_set_sysclk(codec_dai,
69 NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN);
70 if (ret < 0) {
71 dev_err(card->dev, "set sysclk err = %d\n", ret);
72 return -EIO;
73 }
74 }
75
76 return ret;
77}
78
79static const struct snd_kcontrol_new skylake_controls[] = {
80 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
81 SOC_DAPM_PIN_SWITCH("Headset Mic"),
82 SOC_DAPM_PIN_SWITCH("Spk"),
83};
84
85static const struct snd_soc_dapm_widget skylake_widgets[] = {
86 SND_SOC_DAPM_HP("Headphone Jack", NULL),
87 SND_SOC_DAPM_MIC("Headset Mic", NULL),
88 SND_SOC_DAPM_SPK("Spk", NULL),
89 SND_SOC_DAPM_MIC("SoC DMIC", NULL),
90 SND_SOC_DAPM_SINK("WoV Sink"),
91 SND_SOC_DAPM_SPK("DP", NULL),
92 SND_SOC_DAPM_SPK("HDMI", NULL),
93 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
94 platform_clock_control, SND_SOC_DAPM_PRE_PMU |
95 SND_SOC_DAPM_POST_PMD),
96};
97
98static const struct snd_soc_dapm_route skylake_map[] = {
99 /* HP jack connectors - unknown if we have jack detection */
100 { "Headphone Jack", NULL, "HPOL" },
101 { "Headphone Jack", NULL, "HPOR" },
102
103 /* speaker */
104 { "Spk", NULL, "Speaker" },
105
106 /* other jacks */
107 { "MIC", NULL, "Headset Mic" },
108 { "DMic", NULL, "SoC DMIC" },
109
110 {"WoV Sink", NULL, "hwd_in sink"},
111 {"HDMI", NULL, "hif5 Output"},
112 {"DP", NULL, "hif6 Output"},
113
114 /* CODEC BE connections */
115 { "HiFi Playback", NULL, "ssp0 Tx" },
116 { "ssp0 Tx", NULL, "codec0_out" },
117
118 { "Playback", NULL, "ssp1 Tx" },
119 { "ssp1 Tx", NULL, "codec1_out" },
120
121 { "codec0_in", NULL, "ssp1 Rx" },
122 { "ssp1 Rx", NULL, "Capture" },
123
124 /* DMIC */
125 { "dmic01_hifi", NULL, "DMIC01 Rx" },
126 { "DMIC01 Rx", NULL, "DMIC AIF" },
127 { "hifi1", NULL, "iDisp Tx"},
128 { "iDisp Tx", NULL, "iDisp_out"},
129 { "Headphone Jack", NULL, "Platform Clock" },
130 { "Headset Mic", NULL, "Platform Clock" },
131};
132
133static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
134 struct snd_pcm_hw_params *params)
135{
136 struct snd_interval *rate = hw_param_interval(params,
137 SNDRV_PCM_HW_PARAM_RATE);
138 struct snd_interval *channels = hw_param_interval(params,
139 SNDRV_PCM_HW_PARAM_CHANNELS);
140 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
141
142 /* The ADSP will covert the FE rate to 48k, stereo */
143 rate->min = rate->max = 48000;
144 channels->min = channels->max = 2;
145
146 /* set SSP0 to 24 bit */
147 snd_mask_none(fmt);
148 snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
149
150 return 0;
151}
152
153static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
154{
155 int ret;
156 struct snd_soc_codec *codec = rtd->codec;
157
158 /*
159 * Headset buttons map to the google Reference headset.
160 * These can be configured by userspace.
161 */
162 ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack",
163 SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
164 SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset,
165 NULL, 0);
166 if (ret) {
167 dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
168 return ret;
169 }
170
171 nau8825_enable_jack_detect(codec, &skylake_headset);
172
173 snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
174 snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
175
176 return ret;
177}
178
179static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
180{
181 struct snd_soc_dapm_context *dapm;
182 struct snd_soc_component *component = rtd->cpu_dai->component;
183
184 dapm = snd_soc_component_get_dapm(component);
185 snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
186
187 return 0;
188}
189
190static unsigned int rates[] = {
191 48000,
192};
193
194static struct snd_pcm_hw_constraint_list constraints_rates = {
195 .count = ARRAY_SIZE(rates),
196 .list = rates,
197 .mask = 0,
198};
199
200static unsigned int channels[] = {
201 2,
202};
203
204static struct snd_pcm_hw_constraint_list constraints_channels = {
205 .count = ARRAY_SIZE(channels),
206 .list = channels,
207 .mask = 0,
208};
209
210static int skl_fe_startup(struct snd_pcm_substream *substream)
211{
212 struct snd_pcm_runtime *runtime = substream->runtime;
213
214 /*
215 * On this platform for PCM device we support,
216 * 48Khz
217 * stereo
218 * 16 bit audio
219 */
220
221 runtime->hw.channels_max = 2;
222 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
223 &constraints_channels);
224
225 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
226 snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
227
228 snd_pcm_hw_constraint_list(runtime, 0,
229 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
230
231 return 0;
232}
233
234static const struct snd_soc_ops skylake_nau8825_fe_ops = {
235 .startup = skl_fe_startup,
236};
237
238static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream,
239 struct snd_pcm_hw_params *params)
240{
241 struct snd_soc_pcm_runtime *rtd = substream->private_data;
242 struct snd_soc_dai *codec_dai = rtd->codec_dai;
243 int ret;
244
245 ret = snd_soc_dai_set_sysclk(codec_dai,
246 NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN);
247
248 if (ret < 0)
249 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
250
251 return ret;
252}
253
254static struct snd_soc_ops skylake_nau8825_ops = {
255 .hw_params = skylake_nau8825_hw_params,
256};
257
258static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
259 struct snd_pcm_hw_params *params)
260{
261 struct snd_interval *channels = hw_param_interval(params,
262 SNDRV_PCM_HW_PARAM_CHANNELS);
263
264 if (params_channels(params) == 2)
265 channels->min = channels->max = 2;
266 else
267 channels->min = channels->max = 4;
268
269 return 0;
270}
271
272static unsigned int channels_dmic[] = {
273 2, 4,
274};
275
276static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
277 .count = ARRAY_SIZE(channels_dmic),
278 .list = channels_dmic,
279 .mask = 0,
280};
281
282static int skylake_dmic_startup(struct snd_pcm_substream *substream)
283{
284 struct snd_pcm_runtime *runtime = substream->runtime;
285
286 runtime->hw.channels_max = 4;
287 snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
288 &constraints_dmic_channels);
289
290 return snd_pcm_hw_constraint_list(substream->runtime, 0,
291 SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
292}
293
294static struct snd_soc_ops skylake_dmic_ops = {
295 .startup = skylake_dmic_startup,
296};
297
298static unsigned int rates_16000[] = {
299 16000,
300};
301
302static struct snd_pcm_hw_constraint_list constraints_16000 = {
303 .count = ARRAY_SIZE(rates_16000),
304 .list = rates_16000,
305};
306
307static int skylake_refcap_startup(struct snd_pcm_substream *substream)
308{
309 return snd_pcm_hw_constraint_list(substream->runtime, 0,
310 SNDRV_PCM_HW_PARAM_RATE,
311 &constraints_16000);
312}
313
314static struct snd_soc_ops skylaye_refcap_ops = {
315 .startup = skylake_refcap_startup,
316};
317
318/* skylake digital audio interface glue - connects codec <--> CPU */
319static struct snd_soc_dai_link skylake_dais[] = {
320 /* Front End DAI links */
321 {
322 .name = "Skl Audio Port",
323 .stream_name = "Audio",
324 .cpu_dai_name = "System Pin",
325 .platform_name = "0000:00:1f.3",
326 .dynamic = 1,
327 .codec_name = "snd-soc-dummy",
328 .codec_dai_name = "snd-soc-dummy-dai",
329 .nonatomic = 1,
330 .init = skylake_nau8825_fe_init,
331 .trigger = {
332 SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
333 .dpcm_playback = 1,
334 .ops = &skylake_nau8825_fe_ops,
335 },
336 {
337 .name = "Skl Audio Capture Port",
338 .stream_name = "Audio Record",
339 .cpu_dai_name = "System Pin",
340 .platform_name = "0000:00:1f.3",
341 .dynamic = 1,
342 .codec_name = "snd-soc-dummy",
343 .codec_dai_name = "snd-soc-dummy-dai",
344 .nonatomic = 1,
345 .trigger = {
346 SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
347 .dpcm_capture = 1,
348 .ops = &skylake_nau8825_fe_ops,
349 },
350 {
351 .name = "Skl Audio Reference cap",
352 .stream_name = "Wake on Voice",
353 .cpu_dai_name = "Reference Pin",
354 .codec_name = "snd-soc-dummy",
355 .codec_dai_name = "snd-soc-dummy-dai",
356 .platform_name = "0000:00:1f.3",
357 .init = NULL,
358 .dpcm_capture = 1,
359 .ignore_suspend = 1,
360 .nonatomic = 1,
361 .dynamic = 1,
362 .ops = &skylaye_refcap_ops,
363 },
364 {
365 .name = "Skl Audio DMIC cap",
366 .stream_name = "dmiccap",
367 .cpu_dai_name = "DMIC Pin",
368 .codec_name = "snd-soc-dummy",
369 .codec_dai_name = "snd-soc-dummy-dai",
370 .platform_name = "0000:00:1f.3",
371 .init = NULL,
372 .dpcm_capture = 1,
373 .nonatomic = 1,
374 .dynamic = 1,
375 .ops = &skylake_dmic_ops,
376 },
377 {
378 .name = "Skl HDMI Port",
379 .stream_name = "Hdmi",
380 .cpu_dai_name = "HDMI Pin",
381 .codec_name = "snd-soc-dummy",
382 .codec_dai_name = "snd-soc-dummy-dai",
383 .platform_name = "0000:00:1f.3",
384 .dpcm_playback = 1,
385 .init = NULL,
386 .nonatomic = 1,
387 .dynamic = 1,
388 },
389
390 /* Back End DAI links */
391 {
392 /* SSP0 - Codec */
393 .name = "SSP0-Codec",
394 .be_id = 0,
395 .cpu_dai_name = "SSP0 Pin",
396 .platform_name = "0000:00:1f.3",
397 .no_pcm = 1,
398 .codec_name = "MX98357A:00",
399 .codec_dai_name = SKL_MAXIM_CODEC_DAI,
400 .dai_fmt = SND_SOC_DAIFMT_I2S |
401 SND_SOC_DAIFMT_NB_NF |
402 SND_SOC_DAIFMT_CBS_CFS,
403 .ignore_pmdown_time = 1,
404 .be_hw_params_fixup = skylake_ssp_fixup,
405 .dpcm_playback = 1,
406 },
407 {
408 /* SSP1 - Codec */
409 .name = "SSP1-Codec",
410 .be_id = 0,
411 .cpu_dai_name = "SSP1 Pin",
412 .platform_name = "0000:00:1f.3",
413 .no_pcm = 1,
414 .codec_name = "i2c-10508825:00",
415 .codec_dai_name = SKL_NUVOTON_CODEC_DAI,
416 .init = skylake_nau8825_codec_init,
417 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
418 SND_SOC_DAIFMT_CBS_CFS,
419 .ignore_pmdown_time = 1,
420 .be_hw_params_fixup = skylake_ssp_fixup,
421 .ops = &skylake_nau8825_ops,
422 .dpcm_playback = 1,
423 .dpcm_capture = 1,
424 },
425 {
426 .name = "dmic01",
427 .be_id = 1,
428 .cpu_dai_name = "DMIC01 Pin",
429 .codec_name = "dmic-codec",
430 .codec_dai_name = "dmic-hifi",
431 .platform_name = "0000:00:1f.3",
432 .be_hw_params_fixup = skylake_dmic_fixup,
433 .ignore_suspend = 1,
434 .dpcm_capture = 1,
435 .no_pcm = 1,
436 },
437 {
438 .name = "iDisp",
439 .be_id = 3,
440 .cpu_dai_name = "iDisp Pin",
441 .codec_name = "ehdaudio0D2",
442 .codec_dai_name = "intel-hdmi-hifi1",
443 .platform_name = "0000:00:1f.3",
444 .dpcm_playback = 1,
445 .no_pcm = 1,
446 },
447};
448
449/* skylake audio machine driver for SPT + NAU88L25 */
450static struct snd_soc_card skylake_audio_card = {
451 .name = "sklnau8825max",
452 .owner = THIS_MODULE,
453 .dai_link = skylake_dais,
454 .num_links = ARRAY_SIZE(skylake_dais),
455 .controls = skylake_controls,
456 .num_controls = ARRAY_SIZE(skylake_controls),
457 .dapm_widgets = skylake_widgets,
458 .num_dapm_widgets = ARRAY_SIZE(skylake_widgets),
459 .dapm_routes = skylake_map,
460 .num_dapm_routes = ARRAY_SIZE(skylake_map),
461 .fully_routed = true,
462};
463
464static int skylake_audio_probe(struct platform_device *pdev)
465{
466 skylake_audio_card.dev = &pdev->dev;
467
468 return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
469}
470
471static struct platform_driver skylake_audio = {
472 .probe = skylake_audio_probe,
473 .driver = {
474 .name = "skl_nau88l25_max98357a_i2s",
475 .pm = &snd_soc_pm_ops,
476 },
477};
478
479module_platform_driver(skylake_audio)
480
481/* Module information */
482MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
483MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
484MODULE_LICENSE("GPL v2");
485MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s");