1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2019 Intel Corporation.
5 * Intel SOF Machine driver for DA7219 + MAX98373 codec
8 #include <linux/input.h>
9 #include <linux/module.h>
10 #include <sound/pcm.h>
11 #include <sound/pcm_params.h>
12 #include <linux/platform_device.h>
13 #include <sound/soc.h>
14 #include <sound/soc-acpi.h>
15 #include "../../codecs/da7219.h"
16 #include "../../codecs/da7219-aad.h"
17 #include "hda_dsp_common.h"
19 #define DIALOG_CODEC_DAI "da7219-hifi"
20 #define MAX98373_CODEC_DAI "max98373-aif1"
21 #define MAXIM_DEV0_NAME "i2c-MX98373:00"
22 #define MAXIM_DEV1_NAME "i2c-MX98373:01"
25 struct list_head head
;
26 struct snd_soc_dai
*codec_dai
;
31 struct snd_soc_jack headset
;
32 struct list_head hdmi_pcm_list
;
33 struct snd_soc_jack hdmi
[3];
36 static int platform_clock_control(struct snd_soc_dapm_widget
*w
,
37 struct snd_kcontrol
*k
, int event
)
39 struct snd_soc_dapm_context
*dapm
= w
->dapm
;
40 struct snd_soc_card
*card
= dapm
->card
;
41 struct snd_soc_dai
*codec_dai
;
44 codec_dai
= snd_soc_card_get_codec_dai(card
, DIALOG_CODEC_DAI
);
46 dev_err(card
->dev
, "Codec dai not found; Unable to set/unset codec pll\n");
50 if (SND_SOC_DAPM_EVENT_OFF(event
)) {
51 ret
= snd_soc_dai_set_pll(codec_dai
, 0, DA7219_SYSCLK_MCLK
,
54 dev_err(card
->dev
, "failed to stop PLL: %d\n", ret
);
55 } else if (SND_SOC_DAPM_EVENT_ON(event
)) {
56 ret
= snd_soc_dai_set_pll(codec_dai
, 0, DA7219_SYSCLK_PLL_SRM
,
57 0, DA7219_PLL_FREQ_OUT_98304
);
59 dev_err(card
->dev
, "failed to start PLL: %d\n", ret
);
65 static const struct snd_kcontrol_new controls
[] = {
66 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
67 SOC_DAPM_PIN_SWITCH("Headset Mic"),
68 SOC_DAPM_PIN_SWITCH("Left Spk"),
69 SOC_DAPM_PIN_SWITCH("Right Spk"),
72 static const struct snd_soc_dapm_widget widgets
[] = {
73 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
74 SND_SOC_DAPM_MIC("Headset Mic", NULL
),
75 SND_SOC_DAPM_SPK("Left Spk", NULL
),
76 SND_SOC_DAPM_SPK("Right Spk", NULL
),
77 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM
, 0, 0,
78 platform_clock_control
, SND_SOC_DAPM_POST_PMD
|
79 SND_SOC_DAPM_PRE_PMU
),
82 static const struct snd_soc_dapm_route audio_map
[] = {
83 { "Headphone Jack", NULL
, "HPL" },
84 { "Headphone Jack", NULL
, "HPR" },
86 { "Left Spk", NULL
, "Left BE_OUT" },
87 { "Right Spk", NULL
, "Right BE_OUT" },
89 { "MIC", NULL
, "Headset Mic" },
91 { "Headphone Jack", NULL
, "Platform Clock" },
92 { "Headset Mic", NULL
, "Platform Clock" },
95 static struct snd_soc_jack headset
;
97 static int da7219_codec_init(struct snd_soc_pcm_runtime
*rtd
)
99 struct snd_soc_component
*component
= rtd
->codec_dai
->component
;
100 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
101 struct snd_soc_jack
*jack
;
104 /* Configure sysclk for codec */
105 ret
= snd_soc_dai_set_sysclk(codec_dai
, DA7219_CLKSRC_MCLK
, 24000000,
108 dev_err(rtd
->dev
, "can't set codec sysclk configuration\n");
113 * Headset buttons map to the google Reference headset.
114 * These can be configured by userspace.
116 ret
= snd_soc_card_jack_new(rtd
->card
, "Headset Jack",
117 SND_JACK_HEADSET
| SND_JACK_BTN_0
|
118 SND_JACK_BTN_1
| SND_JACK_BTN_2
|
119 SND_JACK_BTN_3
| SND_JACK_LINEOUT
,
122 dev_err(rtd
->dev
, "Headset Jack creation failed: %d\n", ret
);
127 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_0
, KEY_PLAYPAUSE
);
128 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_1
, KEY_VOLUMEUP
);
129 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_2
, KEY_VOLUMEDOWN
);
130 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_3
, KEY_VOICECOMMAND
);
131 da7219_aad_jack_det(component
, jack
);
136 static int ssp1_hw_params(struct snd_pcm_substream
*substream
,
137 struct snd_pcm_hw_params
*params
)
139 struct snd_soc_pcm_runtime
*runtime
= substream
->private_data
;
142 for (j
= 0; j
< runtime
->num_codecs
; j
++) {
143 struct snd_soc_dai
*codec_dai
= runtime
->codec_dais
[j
];
145 if (!strcmp(codec_dai
->component
->name
, MAXIM_DEV0_NAME
)) {
146 /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */
147 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, 0x3, 3, 4, 16);
149 dev_err(runtime
->dev
, "DEV0 TDM slot err:%d\n", ret
);
153 if (!strcmp(codec_dai
->component
->name
, MAXIM_DEV1_NAME
)) {
154 /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */
155 ret
= snd_soc_dai_set_tdm_slot(codec_dai
, 0xC, 3, 4, 16);
157 dev_err(runtime
->dev
, "DEV1 TDM slot err:%d\n", ret
);
166 static struct snd_soc_ops ssp1_ops
= {
167 .hw_params
= ssp1_hw_params
,
170 static struct snd_soc_codec_conf max98373_codec_conf
[] = {
172 .dlc
= COMP_CODEC_CONF(MAXIM_DEV0_NAME
),
173 .name_prefix
= "Right",
176 .dlc
= COMP_CODEC_CONF(MAXIM_DEV1_NAME
),
177 .name_prefix
= "Left",
181 static int hdmi_init(struct snd_soc_pcm_runtime
*rtd
)
183 struct card_private
*ctx
= snd_soc_card_get_drvdata(rtd
->card
);
184 struct snd_soc_dai
*dai
= rtd
->codec_dai
;
185 struct hdmi_pcm
*pcm
;
187 pcm
= devm_kzalloc(rtd
->card
->dev
, sizeof(*pcm
), GFP_KERNEL
);
191 pcm
->device
= dai
->id
;
192 pcm
->codec_dai
= dai
;
194 list_add_tail(&pcm
->head
, &ctx
->hdmi_pcm_list
);
199 static int card_late_probe(struct snd_soc_card
*card
)
201 struct card_private
*ctx
= snd_soc_card_get_drvdata(card
);
202 struct snd_soc_acpi_mach
*mach
= (card
->dev
)->platform_data
;
203 struct hdmi_pcm
*pcm
;
205 if (mach
->mach_params
.common_hdmi_codec_drv
) {
206 pcm
= list_first_entry(&ctx
->hdmi_pcm_list
, struct hdmi_pcm
,
208 return hda_dsp_hdmi_build_controls(card
,
209 pcm
->codec_dai
->component
);
215 SND_SOC_DAILINK_DEF(ssp0_pin
,
216 DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
217 SND_SOC_DAILINK_DEF(ssp0_codec
,
218 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI
)));
220 SND_SOC_DAILINK_DEF(ssp1_pin
,
221 DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin")));
222 SND_SOC_DAILINK_DEF(ssp1_amps
,
224 /* Left */ COMP_CODEC(MAXIM_DEV0_NAME
, MAX98373_CODEC_DAI
),
225 /* Right */ COMP_CODEC(MAXIM_DEV1_NAME
, MAX98373_CODEC_DAI
)));
227 SND_SOC_DAILINK_DEF(dmic_pin
,
228 DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin")));
229 SND_SOC_DAILINK_DEF(dmic_codec
,
230 DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi")));
232 SND_SOC_DAILINK_DEF(idisp1_pin
,
233 DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin")));
234 SND_SOC_DAILINK_DEF(idisp1_codec
,
235 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1")));
237 SND_SOC_DAILINK_DEF(idisp2_pin
,
238 DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin")));
239 SND_SOC_DAILINK_DEF(idisp2_codec
,
240 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2")));
242 SND_SOC_DAILINK_DEF(idisp3_pin
,
243 DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin")));
244 SND_SOC_DAILINK_DEF(idisp3_codec
,
245 DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3")));
247 SND_SOC_DAILINK_DEF(platform
, /* subject to be overridden during probe */
248 DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3")));
250 static struct snd_soc_dai_link dais
[] = {
251 /* Back End DAI links */
253 .name
= "SSP1-Codec",
255 .ignore_pmdown_time
= 1,
258 .dpcm_capture
= 1, /* IV feedback */
260 SND_SOC_DAILINK_REG(ssp1_pin
, ssp1_amps
, platform
),
263 .name
= "SSP0-Codec",
266 .init
= da7219_codec_init
,
267 .ignore_pmdown_time
= 1,
270 SND_SOC_DAILINK_REG(ssp0_pin
, ssp0_codec
, platform
),
278 SND_SOC_DAILINK_REG(dmic_pin
, dmic_codec
, platform
),
286 SND_SOC_DAILINK_REG(idisp1_pin
, idisp1_codec
, platform
),
294 SND_SOC_DAILINK_REG(idisp2_pin
, idisp2_codec
, platform
),
302 SND_SOC_DAILINK_REG(idisp3_pin
, idisp3_codec
, platform
),
306 static struct snd_soc_card card_da7219_m98373
= {
308 .owner
= THIS_MODULE
,
310 .num_links
= ARRAY_SIZE(dais
),
311 .controls
= controls
,
312 .num_controls
= ARRAY_SIZE(controls
),
313 .dapm_widgets
= widgets
,
314 .num_dapm_widgets
= ARRAY_SIZE(widgets
),
315 .dapm_routes
= audio_map
,
316 .num_dapm_routes
= ARRAY_SIZE(audio_map
),
317 .codec_conf
= max98373_codec_conf
,
318 .num_configs
= ARRAY_SIZE(max98373_codec_conf
),
319 .fully_routed
= true,
320 .late_probe
= card_late_probe
,
323 static int audio_probe(struct platform_device
*pdev
)
325 static struct snd_soc_card
*card
;
326 struct snd_soc_acpi_mach
*mach
;
327 struct card_private
*ctx
;
330 ctx
= devm_kzalloc(&pdev
->dev
, sizeof(*ctx
), GFP_ATOMIC
);
334 INIT_LIST_HEAD(&ctx
->hdmi_pcm_list
);
335 card
= (struct snd_soc_card
*)pdev
->id_entry
->driver_data
;
336 card
->dev
= &pdev
->dev
;
338 mach
= (&pdev
->dev
)->platform_data
;
339 ret
= snd_soc_fixup_dai_links_platform_name(card
,
340 mach
->mach_params
.platform
);
344 snd_soc_card_set_drvdata(card
, ctx
);
346 return devm_snd_soc_register_card(&pdev
->dev
, card
);
349 static const struct platform_device_id board_ids
[] = {
351 .name
= "sof_da7219_max98373",
352 .driver_data
= (kernel_ulong_t
)&card_da7219_m98373
,
357 static struct platform_driver audio
= {
358 .probe
= audio_probe
,
360 .name
= "sof_da7219_max98373",
361 .pm
= &snd_soc_pm_ops
,
363 .id_table
= board_ids
,
365 module_platform_driver(audio
)
367 /* Module information */
368 MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver");
369 MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
370 MODULE_LICENSE("GPL v2");
371 MODULE_ALIAS("platform:sof_da7219_max98373");