1 // SPDX-License-Identifier: GPL-2.0+
3 // Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
5 // Authors: Inha Song <ideal.song@samsung.com>
6 // Sylwester Nawrocki <s.nawrocki@samsung.com>
9 #include <linux/gpio.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/module.h>
13 #include <sound/pcm_params.h>
14 #include <sound/soc.h>
17 #include "../codecs/wm5110.h"
20 * The source clock is XCLKOUT with its mux set to the external fixed rate
23 #define MCLK_RATE 24000000U
25 #define TM2_DAI_AIF1 0
26 #define TM2_DAI_AIF2 1
28 struct tm2_machine_priv
{
29 struct snd_soc_component
*component
;
30 unsigned int sysclk_rate
;
31 struct gpio_desc
*gpio_mic_bias
;
34 static int tm2_start_sysclk(struct snd_soc_card
*card
)
36 struct tm2_machine_priv
*priv
= snd_soc_card_get_drvdata(card
);
37 struct snd_soc_component
*component
= priv
->component
;
40 ret
= snd_soc_component_set_pll(component
, WM5110_FLL1_REFCLK
,
41 ARIZONA_FLL_SRC_MCLK1
,
45 dev_err(component
->dev
, "Failed to set FLL1 source: %d\n", ret
);
49 ret
= snd_soc_component_set_pll(component
, WM5110_FLL1
,
50 ARIZONA_FLL_SRC_MCLK1
,
54 dev_err(component
->dev
, "Failed to start FLL1: %d\n", ret
);
58 ret
= snd_soc_component_set_sysclk(component
, ARIZONA_CLK_SYSCLK
,
63 dev_err(component
->dev
, "Failed to set SYSCLK source: %d\n", ret
);
70 static int tm2_stop_sysclk(struct snd_soc_card
*card
)
72 struct tm2_machine_priv
*priv
= snd_soc_card_get_drvdata(card
);
73 struct snd_soc_component
*component
= priv
->component
;
76 ret
= snd_soc_component_set_pll(component
, WM5110_FLL1
, 0, 0, 0);
78 dev_err(component
->dev
, "Failed to stop FLL1: %d\n", ret
);
82 ret
= snd_soc_component_set_sysclk(component
, ARIZONA_CLK_SYSCLK
,
83 ARIZONA_CLK_SRC_FLL1
, 0, 0);
85 dev_err(component
->dev
, "Failed to stop SYSCLK: %d\n", ret
);
92 static int tm2_aif1_hw_params(struct snd_pcm_substream
*substream
,
93 struct snd_pcm_hw_params
*params
)
95 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
96 struct snd_soc_component
*component
= asoc_rtd_to_codec(rtd
, 0)->component
;
97 struct tm2_machine_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
99 switch (params_rate(params
)) {
109 /* Highest possible SYSCLK frequency: 147.456MHz */
110 priv
->sysclk_rate
= 147456000U;
117 /* Highest possible SYSCLK frequency: 135.4752 MHz */
118 priv
->sysclk_rate
= 135475200U;
121 dev_err(component
->dev
, "Not supported sample rate: %d\n",
122 params_rate(params
));
126 return tm2_start_sysclk(rtd
->card
);
129 static struct snd_soc_ops tm2_aif1_ops
= {
130 .hw_params
= tm2_aif1_hw_params
,
133 static int tm2_aif2_hw_params(struct snd_pcm_substream
*substream
,
134 struct snd_pcm_hw_params
*params
)
136 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
137 struct snd_soc_component
*component
= asoc_rtd_to_codec(rtd
, 0)->component
;
138 unsigned int asyncclk_rate
;
141 switch (params_rate(params
)) {
145 /* Highest possible ASYNCCLK frequency: 49.152MHz */
146 asyncclk_rate
= 49152000U;
149 /* Highest possible ASYNCCLK frequency: 45.1584 MHz */
150 asyncclk_rate
= 45158400U;
153 dev_err(component
->dev
, "Not supported sample rate: %d\n",
154 params_rate(params
));
158 ret
= snd_soc_component_set_pll(component
, WM5110_FLL2_REFCLK
,
159 ARIZONA_FLL_SRC_MCLK1
,
163 dev_err(component
->dev
, "Failed to set FLL2 source: %d\n", ret
);
167 ret
= snd_soc_component_set_pll(component
, WM5110_FLL2
,
168 ARIZONA_FLL_SRC_MCLK1
,
172 dev_err(component
->dev
, "Failed to start FLL2: %d\n", ret
);
176 ret
= snd_soc_component_set_sysclk(component
, ARIZONA_CLK_ASYNCCLK
,
177 ARIZONA_CLK_SRC_FLL2
,
181 dev_err(component
->dev
, "Failed to set ASYNCCLK source: %d\n", ret
);
188 static int tm2_aif2_hw_free(struct snd_pcm_substream
*substream
)
190 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
191 struct snd_soc_component
*component
= asoc_rtd_to_codec(rtd
, 0)->component
;
195 ret
= snd_soc_component_set_pll(component
, WM5110_FLL2
, ARIZONA_FLL_SRC_MCLK1
,
198 dev_err(component
->dev
, "Failed to stop FLL2: %d\n", ret
);
203 static struct snd_soc_ops tm2_aif2_ops
= {
204 .hw_params
= tm2_aif2_hw_params
,
205 .hw_free
= tm2_aif2_hw_free
,
208 static int tm2_hdmi_hw_params(struct snd_pcm_substream
*substream
,
209 struct snd_pcm_hw_params
*params
)
211 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
212 struct snd_soc_dai
*cpu_dai
= asoc_rtd_to_cpu(rtd
, 0);
216 bitwidth
= snd_pcm_format_width(params_format(params
));
218 dev_err(rtd
->card
->dev
, "Invalid bit-width: %d\n", bitwidth
);
230 dev_err(rtd
->card
->dev
, "Unsupported bit-width: %d\n", bitwidth
);
234 switch (params_rate(params
)) {
240 dev_err(rtd
->card
->dev
, "Unsupported sample rate: %d\n",
241 params_rate(params
));
245 ret
= snd_soc_dai_set_sysclk(cpu_dai
, SAMSUNG_I2S_OPCLK
,
246 0, SAMSUNG_I2S_OPCLK_PCLK
);
250 ret
= snd_soc_dai_set_clkdiv(cpu_dai
, SAMSUNG_I2S_DIV_BCLK
, bfs
);
257 static struct snd_soc_ops tm2_hdmi_ops
= {
258 .hw_params
= tm2_hdmi_hw_params
,
261 static int tm2_mic_bias(struct snd_soc_dapm_widget
*w
,
262 struct snd_kcontrol
*kcontrol
, int event
)
264 struct snd_soc_card
*card
= w
->dapm
->card
;
265 struct tm2_machine_priv
*priv
= snd_soc_card_get_drvdata(card
);
268 case SND_SOC_DAPM_PRE_PMU
:
269 gpiod_set_value_cansleep(priv
->gpio_mic_bias
, 1);
271 case SND_SOC_DAPM_POST_PMD
:
272 gpiod_set_value_cansleep(priv
->gpio_mic_bias
, 0);
279 static int tm2_set_bias_level(struct snd_soc_card
*card
,
280 struct snd_soc_dapm_context
*dapm
,
281 enum snd_soc_bias_level level
)
283 struct snd_soc_pcm_runtime
*rtd
;
285 rtd
= snd_soc_get_pcm_runtime(card
, &card
->dai_link
[0]);
287 if (dapm
->dev
!= asoc_rtd_to_codec(rtd
, 0)->dev
)
291 case SND_SOC_BIAS_STANDBY
:
292 if (card
->dapm
.bias_level
== SND_SOC_BIAS_OFF
)
293 tm2_start_sysclk(card
);
295 case SND_SOC_BIAS_OFF
:
296 tm2_stop_sysclk(card
);
305 static struct snd_soc_aux_dev tm2_speaker_amp_dev
;
307 static int tm2_late_probe(struct snd_soc_card
*card
)
309 struct tm2_machine_priv
*priv
= snd_soc_card_get_drvdata(card
);
310 unsigned int ch_map
[] = { 0, 1 };
311 struct snd_soc_dai
*amp_pdm_dai
;
312 struct snd_soc_pcm_runtime
*rtd
;
313 struct snd_soc_dai
*aif1_dai
;
314 struct snd_soc_dai
*aif2_dai
;
317 rtd
= snd_soc_get_pcm_runtime(card
, &card
->dai_link
[TM2_DAI_AIF1
]);
318 aif1_dai
= asoc_rtd_to_codec(rtd
, 0);
319 priv
->component
= asoc_rtd_to_codec(rtd
, 0)->component
;
321 ret
= snd_soc_dai_set_sysclk(aif1_dai
, ARIZONA_CLK_SYSCLK
, 0, 0);
323 dev_err(aif1_dai
->dev
, "Failed to set SYSCLK: %d\n", ret
);
327 rtd
= snd_soc_get_pcm_runtime(card
, &card
->dai_link
[TM2_DAI_AIF2
]);
328 aif2_dai
= asoc_rtd_to_codec(rtd
, 0);
330 ret
= snd_soc_dai_set_sysclk(aif2_dai
, ARIZONA_CLK_ASYNCCLK
, 0, 0);
332 dev_err(aif2_dai
->dev
, "Failed to set ASYNCCLK: %d\n", ret
);
336 amp_pdm_dai
= snd_soc_find_dai(&tm2_speaker_amp_dev
.dlc
);
340 /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */
341 ret
= snd_soc_dai_set_channel_map(amp_pdm_dai
, ARRAY_SIZE(ch_map
),
346 ret
= snd_soc_dai_set_tdm_slot(amp_pdm_dai
, 0x3, 0x0, 2, 16);
353 static const struct snd_kcontrol_new tm2_controls
[] = {
354 SOC_DAPM_PIN_SWITCH("HP"),
355 SOC_DAPM_PIN_SWITCH("SPK"),
356 SOC_DAPM_PIN_SWITCH("RCV"),
357 SOC_DAPM_PIN_SWITCH("VPS"),
358 SOC_DAPM_PIN_SWITCH("HDMI"),
360 SOC_DAPM_PIN_SWITCH("Main Mic"),
361 SOC_DAPM_PIN_SWITCH("Sub Mic"),
362 SOC_DAPM_PIN_SWITCH("Third Mic"),
364 SOC_DAPM_PIN_SWITCH("Headset Mic"),
367 static const struct snd_soc_dapm_widget tm2_dapm_widgets
[] = {
368 SND_SOC_DAPM_HP("HP", NULL
),
369 SND_SOC_DAPM_SPK("SPK", NULL
),
370 SND_SOC_DAPM_SPK("RCV", NULL
),
371 SND_SOC_DAPM_LINE("VPS", NULL
),
372 SND_SOC_DAPM_LINE("HDMI", NULL
),
374 SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias
),
375 SND_SOC_DAPM_MIC("Sub Mic", NULL
),
376 SND_SOC_DAPM_MIC("Third Mic", NULL
),
378 SND_SOC_DAPM_MIC("Headset Mic", NULL
),
381 static const struct snd_soc_component_driver tm2_component
= {
385 static struct snd_soc_dai_driver tm2_ext_dai
[] = {
387 .name
= "Voice call",
393 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
|
394 SNDRV_PCM_RATE_48000
),
395 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
402 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
|
403 SNDRV_PCM_RATE_48000
),
404 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
414 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
),
415 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
422 .rates
= (SNDRV_PCM_RATE_8000
| SNDRV_PCM_RATE_16000
),
423 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
428 SND_SOC_DAILINK_DEFS(aif1
,
429 DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI
)),
430 DAILINK_COMP_ARRAY(COMP_CODEC(NULL
, "wm5110-aif1")),
431 DAILINK_COMP_ARRAY(COMP_EMPTY()));
433 SND_SOC_DAILINK_DEFS(voice
,
434 DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI
)),
435 DAILINK_COMP_ARRAY(COMP_CODEC(NULL
, "wm5110-aif2")),
436 DAILINK_COMP_ARRAY(COMP_EMPTY()));
438 SND_SOC_DAILINK_DEFS(bt
,
439 DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI
)),
440 DAILINK_COMP_ARRAY(COMP_CODEC(NULL
, "wm5110-aif3")),
441 DAILINK_COMP_ARRAY(COMP_EMPTY()));
443 SND_SOC_DAILINK_DEFS(hdmi
,
444 DAILINK_COMP_ARRAY(COMP_EMPTY()),
445 DAILINK_COMP_ARRAY(COMP_EMPTY()),
446 DAILINK_COMP_ARRAY(COMP_EMPTY()));
448 static struct snd_soc_dai_link tm2_dai_links
[] = {
450 .name
= "WM5110 AIF1",
451 .stream_name
= "HiFi Primary",
452 .ops
= &tm2_aif1_ops
,
453 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
454 SND_SOC_DAIFMT_CBM_CFM
,
455 SND_SOC_DAILINK_REG(aif1
),
457 .name
= "WM5110 Voice",
458 .stream_name
= "Voice call",
459 .ops
= &tm2_aif2_ops
,
460 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
461 SND_SOC_DAIFMT_CBM_CFM
,
463 SND_SOC_DAILINK_REG(voice
),
466 .stream_name
= "Bluetooth",
467 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
468 SND_SOC_DAIFMT_CBM_CFM
,
470 SND_SOC_DAILINK_REG(bt
),
473 .stream_name
= "i2s1",
474 .ops
= &tm2_hdmi_ops
,
475 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
476 SND_SOC_DAIFMT_CBS_CFS
,
477 SND_SOC_DAILINK_REG(hdmi
),
481 static struct snd_soc_card tm2_card
= {
482 .owner
= THIS_MODULE
,
484 .dai_link
= tm2_dai_links
,
485 .controls
= tm2_controls
,
486 .num_controls
= ARRAY_SIZE(tm2_controls
),
487 .dapm_widgets
= tm2_dapm_widgets
,
488 .num_dapm_widgets
= ARRAY_SIZE(tm2_dapm_widgets
),
489 .aux_dev
= &tm2_speaker_amp_dev
,
492 .late_probe
= tm2_late_probe
,
493 .set_bias_level
= tm2_set_bias_level
,
496 static int tm2_probe(struct platform_device
*pdev
)
498 struct device_node
*cpu_dai_node
[2] = {};
499 struct device_node
*codec_dai_node
[2] = {};
500 const char *cells_name
= NULL
;
501 struct device
*dev
= &pdev
->dev
;
502 struct snd_soc_card
*card
= &tm2_card
;
503 struct tm2_machine_priv
*priv
;
504 struct of_phandle_args args
;
505 struct snd_soc_dai_link
*dai_link
;
506 int num_codecs
, ret
, i
;
508 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
512 snd_soc_card_set_drvdata(card
, priv
);
515 priv
->gpio_mic_bias
= devm_gpiod_get(dev
, "mic-bias", GPIOD_OUT_HIGH
);
516 if (IS_ERR(priv
->gpio_mic_bias
)) {
517 dev_err(dev
, "Failed to get mic bias gpio\n");
518 return PTR_ERR(priv
->gpio_mic_bias
);
521 ret
= snd_soc_of_parse_card_name(card
, "model");
523 dev_err(dev
, "Card name is not specified\n");
527 ret
= snd_soc_of_parse_audio_routing(card
, "samsung,audio-routing");
529 dev_err(dev
, "Audio routing is not specified or invalid\n");
533 card
->aux_dev
[0].dlc
.of_node
= of_parse_phandle(dev
->of_node
,
534 "audio-amplifier", 0);
535 if (!card
->aux_dev
[0].dlc
.of_node
) {
536 dev_err(dev
, "audio-amplifier property invalid or missing\n");
540 num_codecs
= of_count_phandle_with_args(dev
->of_node
, "audio-codec",
543 /* Skip the HDMI link if not specified in DT */
544 if (num_codecs
> 1) {
545 card
->num_links
= ARRAY_SIZE(tm2_dai_links
);
546 cells_name
= "#sound-dai-cells";
548 card
->num_links
= ARRAY_SIZE(tm2_dai_links
) - 1;
551 for (i
= 0; i
< num_codecs
; i
++) {
552 struct of_phandle_args args
;
554 ret
= of_parse_phandle_with_args(dev
->of_node
, "i2s-controller",
555 cells_name
, i
, &args
);
557 dev_err(dev
, "i2s-controller property parse error: %d\n", i
);
561 cpu_dai_node
[i
] = args
.np
;
563 codec_dai_node
[i
] = of_parse_phandle(dev
->of_node
,
565 if (!codec_dai_node
[i
]) {
566 dev_err(dev
, "audio-codec property parse error\n");
572 /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */
573 for_each_card_prelinks(card
, i
, dai_link
) {
574 unsigned int dai_index
= 0; /* WM5110 */
576 dai_link
->cpus
->name
= NULL
;
577 dai_link
->platforms
->name
= NULL
;
579 if (num_codecs
> 1 && i
== card
->num_links
- 1)
580 dai_index
= 1; /* HDMI */
582 dai_link
->codecs
->of_node
= codec_dai_node
[dai_index
];
583 dai_link
->cpus
->of_node
= cpu_dai_node
[dai_index
];
584 dai_link
->platforms
->of_node
= cpu_dai_node
[dai_index
];
587 if (num_codecs
> 1) {
588 /* HDMI DAI link (I2S1) */
589 i
= card
->num_links
- 1;
591 ret
= of_parse_phandle_with_fixed_args(dev
->of_node
,
592 "audio-codec", 0, 1, &args
);
594 dev_err(dev
, "audio-codec property parse error\n");
598 ret
= snd_soc_get_dai_name(&args
, &card
->dai_link
[i
].codecs
->dai_name
);
600 dev_err(dev
, "Unable to get codec_dai_name\n");
605 ret
= devm_snd_soc_register_component(dev
, &tm2_component
,
606 tm2_ext_dai
, ARRAY_SIZE(tm2_ext_dai
));
608 dev_err(dev
, "Failed to register component: %d\n", ret
);
612 ret
= devm_snd_soc_register_card(dev
, card
);
614 if (ret
!= -EPROBE_DEFER
)
615 dev_err(dev
, "Failed to register card: %d\n", ret
);
620 for (i
= 0; i
< num_codecs
; i
++) {
621 of_node_put(codec_dai_node
[i
]);
622 of_node_put(cpu_dai_node
[i
]);
625 of_node_put(card
->aux_dev
[0].dlc
.of_node
);
630 static int tm2_pm_prepare(struct device
*dev
)
632 struct snd_soc_card
*card
= dev_get_drvdata(dev
);
634 return tm2_stop_sysclk(card
);
637 static void tm2_pm_complete(struct device
*dev
)
639 struct snd_soc_card
*card
= dev_get_drvdata(dev
);
641 tm2_start_sysclk(card
);
644 static const struct dev_pm_ops tm2_pm_ops
= {
645 .prepare
= tm2_pm_prepare
,
646 .suspend
= snd_soc_suspend
,
647 .resume
= snd_soc_resume
,
648 .complete
= tm2_pm_complete
,
649 .freeze
= snd_soc_suspend
,
650 .thaw
= snd_soc_resume
,
651 .poweroff
= snd_soc_poweroff
,
652 .restore
= snd_soc_resume
,
655 static const struct of_device_id tm2_of_match
[] = {
656 { .compatible
= "samsung,tm2-audio" },
659 MODULE_DEVICE_TABLE(of
, tm2_of_match
);
661 static struct platform_driver tm2_driver
= {
665 .of_match_table
= tm2_of_match
,
669 module_platform_driver(tm2_driver
);
671 MODULE_AUTHOR("Inha Song <ideal.song@samsung.com>");
672 MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support");
673 MODULE_LICENSE("GPL v2");