1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright (c) 2020, The Linux Foundation. All rights reserved.
5 // sc7180.c -- ALSA SoC Machine driver for SC7180
7 #include <dt-bindings/sound/sc7180-lpass.h>
8 #include <linux/gpio.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/platform_device.h>
13 #include <sound/core.h>
14 #include <sound/jack.h>
15 #include <sound/pcm.h>
16 #include <sound/soc.h>
17 #include <uapi/linux/input-event-codes.h>
19 #include "../codecs/rt5682.h"
23 #define DEFAULT_MCLK_RATE 19200000
24 #define RT5682_PLL1_FREQ (48000 * 512)
26 #define DRIVER_NAME "SC7180"
28 struct sc7180_snd_data
{
29 struct snd_soc_card card
;
30 u32 pri_mi2s_clk_count
;
31 struct snd_soc_jack hs_jack
;
32 struct snd_soc_jack hdmi_jack
;
33 struct gpio_desc
*dmic_sel
;
37 static void sc7180_jack_free(struct snd_jack
*jack
)
39 struct snd_soc_component
*component
= jack
->private_data
;
41 snd_soc_component_set_jack(component
, NULL
, NULL
);
44 static int sc7180_headset_init(struct snd_soc_pcm_runtime
*rtd
)
46 struct snd_soc_card
*card
= rtd
->card
;
47 struct sc7180_snd_data
*pdata
= snd_soc_card_get_drvdata(card
);
48 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(rtd
, 0);
49 struct snd_soc_component
*component
= codec_dai
->component
;
50 struct snd_jack
*jack
;
53 rval
= snd_soc_card_jack_new(
57 SND_JACK_BTN_0
| SND_JACK_BTN_1
|
58 SND_JACK_BTN_2
| SND_JACK_BTN_3
,
59 &pdata
->hs_jack
, NULL
, 0);
62 dev_err(card
->dev
, "Unable to add Headset Jack\n");
66 jack
= pdata
->hs_jack
.jack
;
68 snd_jack_set_key(jack
, SND_JACK_BTN_0
, KEY_PLAYPAUSE
);
69 snd_jack_set_key(jack
, SND_JACK_BTN_1
, KEY_VOICECOMMAND
);
70 snd_jack_set_key(jack
, SND_JACK_BTN_2
, KEY_VOLUMEUP
);
71 snd_jack_set_key(jack
, SND_JACK_BTN_3
, KEY_VOLUMEDOWN
);
73 jack
->private_data
= component
;
74 jack
->private_free
= sc7180_jack_free
;
76 return snd_soc_component_set_jack(component
, &pdata
->hs_jack
, NULL
);
79 static int sc7180_hdmi_init(struct snd_soc_pcm_runtime
*rtd
)
81 struct snd_soc_card
*card
= rtd
->card
;
82 struct sc7180_snd_data
*pdata
= snd_soc_card_get_drvdata(card
);
83 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(rtd
, 0);
84 struct snd_soc_component
*component
= codec_dai
->component
;
85 struct snd_jack
*jack
;
88 rval
= snd_soc_card_jack_new(
91 &pdata
->hdmi_jack
, NULL
, 0);
94 dev_err(card
->dev
, "Unable to add HDMI Jack\n");
98 jack
= pdata
->hdmi_jack
.jack
;
99 jack
->private_data
= component
;
100 jack
->private_free
= sc7180_jack_free
;
102 return snd_soc_component_set_jack(component
, &pdata
->hdmi_jack
, NULL
);
105 static int sc7180_init(struct snd_soc_pcm_runtime
*rtd
)
107 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
109 switch (cpu_dai
->id
) {
111 return sc7180_headset_init(rtd
);
115 return sc7180_hdmi_init(rtd
);
117 dev_err(rtd
->dev
, "%s: invalid dai id 0x%x\n", __func__
,
124 static int sc7180_snd_startup(struct snd_pcm_substream
*substream
)
126 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
127 struct snd_soc_card
*card
= rtd
->card
;
128 struct sc7180_snd_data
*data
= snd_soc_card_get_drvdata(card
);
129 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
130 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(rtd
, 0);
133 switch (cpu_dai
->id
) {
135 if (++data
->pri_mi2s_clk_count
== 1) {
136 snd_soc_dai_set_sysclk(cpu_dai
,
139 SNDRV_PCM_STREAM_PLAYBACK
);
142 snd_soc_dai_set_fmt(codec_dai
,
143 SND_SOC_DAIFMT_CBS_CFS
|
144 SND_SOC_DAIFMT_NB_NF
|
147 /* Configure PLL1 for codec */
148 ret
= snd_soc_dai_set_pll(codec_dai
, 0, RT5682_PLL1_S_MCLK
,
149 DEFAULT_MCLK_RATE
, RT5682_PLL1_FREQ
);
151 dev_err(rtd
->dev
, "can't set codec pll: %d\n", ret
);
155 /* Configure sysclk for codec */
156 ret
= snd_soc_dai_set_sysclk(codec_dai
, RT5682_SCLK_S_PLL1
,
160 dev_err(rtd
->dev
, "snd_soc_dai_set_sysclk err = %d\n",
169 dev_err(rtd
->dev
, "%s: invalid dai id 0x%x\n", __func__
,
176 static int dmic_get(struct snd_kcontrol
*kcontrol
,
177 struct snd_ctl_elem_value
*ucontrol
)
179 struct snd_soc_dapm_context
*dapm
= snd_soc_dapm_kcontrol_dapm(kcontrol
);
180 struct sc7180_snd_data
*data
= snd_soc_card_get_drvdata(dapm
->card
);
182 ucontrol
->value
.integer
.value
[0] = data
->dmic_switch
;
186 static int dmic_set(struct snd_kcontrol
*kcontrol
,
187 struct snd_ctl_elem_value
*ucontrol
)
189 struct snd_soc_dapm_context
*dapm
= snd_soc_dapm_kcontrol_dapm(kcontrol
);
190 struct sc7180_snd_data
*data
= snd_soc_card_get_drvdata(dapm
->card
);
192 data
->dmic_switch
= ucontrol
->value
.integer
.value
[0];
193 gpiod_set_value(data
->dmic_sel
, data
->dmic_switch
);
197 static void sc7180_snd_shutdown(struct snd_pcm_substream
*substream
)
199 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
200 struct snd_soc_card
*card
= rtd
->card
;
201 struct sc7180_snd_data
*data
= snd_soc_card_get_drvdata(card
);
202 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
204 switch (cpu_dai
->id
) {
206 if (--data
->pri_mi2s_clk_count
== 0) {
207 snd_soc_dai_set_sysclk(cpu_dai
,
210 SNDRV_PCM_STREAM_PLAYBACK
);
218 dev_err(rtd
->dev
, "%s: invalid dai id 0x%x\n", __func__
,
224 static int sc7180_adau7002_init(struct snd_soc_pcm_runtime
*rtd
)
226 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
228 switch (cpu_dai
->id
) {
234 return sc7180_hdmi_init(rtd
);
236 dev_err(rtd
->dev
, "%s: invalid dai id 0x%x\n", __func__
,
243 static int sc7180_adau7002_snd_startup(struct snd_pcm_substream
*substream
)
245 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
246 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
247 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(rtd
, 0);
248 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
250 switch (cpu_dai
->id
) {
252 snd_soc_dai_set_fmt(codec_dai
,
253 SND_SOC_DAIFMT_CBS_CFS
|
254 SND_SOC_DAIFMT_NB_NF
|
256 runtime
->hw
.formats
= SNDRV_PCM_FMTBIT_S32_LE
;
257 snd_pcm_hw_constraint_msbits(runtime
, 0, 32, 32);
265 dev_err(rtd
->dev
, "%s: invalid dai id 0x%x\n", __func__
,
272 static const struct snd_soc_ops sc7180_ops
= {
273 .startup
= sc7180_snd_startup
,
274 .shutdown
= sc7180_snd_shutdown
,
277 static const struct snd_soc_ops sc7180_adau7002_ops
= {
278 .startup
= sc7180_adau7002_snd_startup
,
281 static const struct snd_soc_dapm_widget sc7180_snd_widgets
[] = {
282 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
283 SND_SOC_DAPM_MIC("Headset Mic", NULL
),
286 static const struct snd_soc_dapm_widget sc7180_adau7002_snd_widgets
[] = {
287 SND_SOC_DAPM_MIC("DMIC", NULL
),
290 static const char * const dmic_mux_text
[] = {
295 static SOC_ENUM_SINGLE_DECL(sc7180_dmic_enum
,
296 SND_SOC_NOPM
, 0, dmic_mux_text
);
298 static const struct snd_kcontrol_new sc7180_dmic_mux_control
=
299 SOC_DAPM_ENUM_EXT("DMIC Select Mux", sc7180_dmic_enum
,
302 static const struct snd_soc_dapm_widget sc7180_snd_dual_mic_widgets
[] = {
303 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
304 SND_SOC_DAPM_MIC("Headset Mic", NULL
),
305 SND_SOC_DAPM_MIC("DMIC", NULL
),
306 SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM
, 0, 0, &sc7180_dmic_mux_control
),
309 static const struct snd_soc_dapm_route sc7180_snd_dual_mic_audio_route
[] = {
310 {"Dmic Mux", "Front Mic", "DMIC"},
311 {"Dmic Mux", "Rear Mic", "DMIC"},
314 static int sc7180_snd_platform_probe(struct platform_device
*pdev
)
316 struct snd_soc_card
*card
;
317 struct sc7180_snd_data
*data
;
318 struct device
*dev
= &pdev
->dev
;
319 struct snd_soc_dai_link
*link
;
322 bool no_headphone
= false;
324 /* Allocate the private data */
325 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
330 snd_soc_card_set_drvdata(card
, data
);
332 card
->owner
= THIS_MODULE
;
333 card
->driver_name
= DRIVER_NAME
;
335 card
->dapm_widgets
= sc7180_snd_widgets
;
336 card
->num_dapm_widgets
= ARRAY_SIZE(sc7180_snd_widgets
);
338 if (of_property_read_bool(dev
->of_node
, "dmic-gpios")) {
339 card
->dapm_widgets
= sc7180_snd_dual_mic_widgets
,
340 card
->num_dapm_widgets
= ARRAY_SIZE(sc7180_snd_dual_mic_widgets
),
341 card
->dapm_routes
= sc7180_snd_dual_mic_audio_route
,
342 card
->num_dapm_routes
= ARRAY_SIZE(sc7180_snd_dual_mic_audio_route
),
343 data
->dmic_sel
= devm_gpiod_get(&pdev
->dev
, "dmic", GPIOD_OUT_LOW
);
344 if (IS_ERR(data
->dmic_sel
)) {
345 dev_err(&pdev
->dev
, "DMIC gpio failed err=%ld\n", PTR_ERR(data
->dmic_sel
));
346 return PTR_ERR(data
->dmic_sel
);
350 if (of_device_is_compatible(dev
->of_node
, "google,sc7180-coachz")) {
352 card
->dapm_widgets
= sc7180_adau7002_snd_widgets
;
353 card
->num_dapm_widgets
= ARRAY_SIZE(sc7180_adau7002_snd_widgets
);
356 ret
= qcom_snd_parse_of(card
);
360 for_each_card_prelinks(card
, i
, link
) {
362 link
->ops
= &sc7180_adau7002_ops
;
363 link
->init
= sc7180_adau7002_init
;
365 link
->ops
= &sc7180_ops
;
366 link
->init
= sc7180_init
;
370 return devm_snd_soc_register_card(dev
, card
);
373 static const struct of_device_id sc7180_snd_device_id
[] = {
374 {.compatible
= "google,sc7180-trogdor"},
375 {.compatible
= "google,sc7180-coachz"},
378 MODULE_DEVICE_TABLE(of
, sc7180_snd_device_id
);
380 static struct platform_driver sc7180_snd_driver
= {
381 .probe
= sc7180_snd_platform_probe
,
383 .name
= "msm-snd-sc7180",
384 .of_match_table
= sc7180_snd_device_id
,
385 .pm
= &snd_soc_pm_ops
,
388 module_platform_driver(sc7180_snd_driver
);
390 MODULE_DESCRIPTION("sc7180 ASoC Machine Driver");
391 MODULE_LICENSE("GPL v2");