1// SPDX-License-Identifier: GPL-2.0+
2//
3// Midas audio support
4//
5// Copyright (C) 2018 Simon Shields <simon@lineageos.org>
6// Copyright (C) 2020 Samsung Electronics Co., Ltd.
7
8#include <linux/clk.h>
9#include <linux/gpio/consumer.h>
10#include <linux/mfd/wm8994/registers.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/regulator/consumer.h>
14#include <sound/jack.h>
15#include <sound/soc.h>
16#include <sound/soc-dapm.h>
17
18#include "i2s.h"
19#include "../codecs/wm8994.h"
20
21/*
22 * The MCLK1 clock source is XCLKOUT with its mux set to the external fixed rate
23 * oscillator (XXTI).
24 */
25#define MCLK1_RATE 24000000U
26#define MCLK2_RATE 32768U
27#define DEFAULT_FLL1_RATE 11289600U
28
29struct midas_priv {
30 struct regulator *reg_mic_bias;
31 struct regulator *reg_submic_bias;
32 struct gpio_desc *gpio_fm_sel;
33 struct gpio_desc *gpio_lineout_sel;
34 unsigned int fll1_rate;
35
36 struct snd_soc_jack headset_jack;
37};
38
39static struct snd_soc_jack_pin headset_jack_pins[] = {
40 {
41 .pin = "Headphone",
42 .mask = SND_JACK_HEADPHONE,
43 },
44 {
45 .pin = "Headset Mic",
46 .mask = SND_JACK_MICROPHONE,
47 },
48};
49
50static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
51{
52 struct snd_soc_card *card = rtd->card;
53 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
54 struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
55 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
56 int ret;
57
58 if (!rate)
59 rate = priv->fll1_rate;
60 /*
61 * If no new rate is requested, set FLL1 to a sane default for jack
62 * detection.
63 */
64 if (!rate)
65 rate = DEFAULT_FLL1_RATE;
66
67 if (rate != priv->fll1_rate && priv->fll1_rate) {
68 /* while reconfiguring, switch to MCLK2 for SYSCLK */
69 ret = snd_soc_dai_set_sysclk(dai: aif1_dai, WM8994_SYSCLK_MCLK2,
70 MCLK2_RATE, SND_SOC_CLOCK_IN);
71 if (ret < 0) {
72 dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret);
73 return ret;
74 }
75 }
76
77 ret = snd_soc_dai_set_pll(dai: aif1_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
78 MCLK1_RATE, freq_out: rate);
79 if (ret < 0) {
80 dev_err(card->dev, "Failed to set FLL1 rate: %d\n", ret);
81 return ret;
82 }
83 priv->fll1_rate = rate;
84
85 ret = snd_soc_dai_set_sysclk(dai: aif1_dai, WM8994_SYSCLK_FLL1,
86 freq: priv->fll1_rate, SND_SOC_CLOCK_IN);
87 if (ret < 0) {
88 dev_err(card->dev, "Failed to set SYSCLK source: %d\n", ret);
89 return ret;
90 }
91
92 ret = snd_soc_dai_set_sysclk(dai: cpu_dai, SAMSUNG_I2S_OPCLK, freq: 0,
93 SAMSUNG_I2S_OPCLK_PCLK);
94 if (ret < 0) {
95 dev_err(card->dev, "Failed to set OPCLK source: %d\n", ret);
96 return ret;
97 }
98
99 return 0;
100}
101
102static int midas_stop_fll1(struct snd_soc_pcm_runtime *rtd)
103{
104 struct snd_soc_card *card = rtd->card;
105 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
106 struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
107 int ret;
108
109 ret = snd_soc_dai_set_sysclk(dai: aif1_dai, WM8994_SYSCLK_MCLK2,
110 MCLK2_RATE, SND_SOC_CLOCK_IN);
111 if (ret < 0) {
112 dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret);
113 return ret;
114 }
115
116 ret = snd_soc_dai_set_pll(dai: aif1_dai, WM8994_FLL1, source: 0, freq_in: 0, freq_out: 0);
117 if (ret < 0) {
118 dev_err(card->dev, "Unable to stop FLL1: %d\n", ret);
119 return ret;
120 }
121
122 priv->fll1_rate = 0;
123
124 return 0;
125}
126
127static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
128 struct snd_pcm_hw_params *params)
129{
130 struct snd_soc_pcm_runtime *rtd = substream->private_data;
131 unsigned int pll_out;
132
133 /* AIF1CLK should be at least 3MHz for "optimal performance" */
134 if (params_rate(p: params) == 8000 || params_rate(p: params) == 11025)
135 pll_out = params_rate(p: params) * 512;
136 else
137 pll_out = params_rate(p: params) * 256;
138
139 return midas_start_fll1(rtd, rate: pll_out);
140}
141
142static const struct snd_soc_ops midas_aif1_ops = {
143 .hw_params = midas_aif1_hw_params,
144};
145
146/*
147 * We only have a single external speaker, so mix stereo data
148 * to a single mono stream.
149 */
150static int midas_ext_spkmode(struct snd_soc_dapm_widget *w,
151 struct snd_kcontrol *kcontrol, int event)
152{
153 struct snd_soc_component *codec = snd_soc_dapm_to_component(dapm: w->dapm);
154 int ret = 0;
155
156 switch (event) {
157 case SND_SOC_DAPM_PRE_PMU:
158 ret = snd_soc_component_update_bits(component: codec, WM8994_SPKOUT_MIXERS,
159 WM8994_SPKMIXR_TO_SPKOUTL_MASK,
160 WM8994_SPKMIXR_TO_SPKOUTL);
161 break;
162 case SND_SOC_DAPM_POST_PMD:
163 ret = snd_soc_component_update_bits(component: codec, WM8994_SPKOUT_MIXERS,
164 WM8994_SPKMIXR_TO_SPKOUTL_MASK,
165 val: 0);
166 break;
167 }
168
169 return ret;
170}
171
172static int midas_mic_bias(struct snd_soc_dapm_widget *w,
173 struct snd_kcontrol *kcontrol, int event)
174{
175 struct snd_soc_card *card = w->dapm->card;
176 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
177
178 switch (event) {
179 case SND_SOC_DAPM_PRE_PMU:
180 return regulator_enable(regulator: priv->reg_mic_bias);
181 case SND_SOC_DAPM_POST_PMD:
182 return regulator_disable(regulator: priv->reg_mic_bias);
183 }
184
185 return 0;
186}
187
188static int midas_submic_bias(struct snd_soc_dapm_widget *w,
189 struct snd_kcontrol *kcontrol, int event)
190{
191 struct snd_soc_card *card = w->dapm->card;
192 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
193
194 switch (event) {
195 case SND_SOC_DAPM_PRE_PMU:
196 return regulator_enable(regulator: priv->reg_submic_bias);
197 case SND_SOC_DAPM_POST_PMD:
198 return regulator_disable(regulator: priv->reg_submic_bias);
199 }
200
201 return 0;
202}
203
204static int midas_fm_set(struct snd_soc_dapm_widget *w,
205 struct snd_kcontrol *kcontrol, int event)
206{
207 struct snd_soc_card *card = w->dapm->card;
208 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
209
210 if (!priv->gpio_fm_sel)
211 return 0;
212
213 switch (event) {
214 case SND_SOC_DAPM_PRE_PMU:
215 gpiod_set_value_cansleep(desc: priv->gpio_fm_sel, value: 1);
216 break;
217 case SND_SOC_DAPM_POST_PMD:
218 gpiod_set_value_cansleep(desc: priv->gpio_fm_sel, value: 0);
219 break;
220 }
221
222 return 0;
223}
224
225static int midas_line_set(struct snd_soc_dapm_widget *w,
226 struct snd_kcontrol *kcontrol, int event)
227{
228 struct snd_soc_card *card = w->dapm->card;
229 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
230
231 if (!priv->gpio_lineout_sel)
232 return 0;
233
234 switch (event) {
235 case SND_SOC_DAPM_PRE_PMU:
236 gpiod_set_value_cansleep(desc: priv->gpio_lineout_sel, value: 1);
237 break;
238 case SND_SOC_DAPM_POST_PMD:
239 gpiod_set_value_cansleep(desc: priv->gpio_lineout_sel, value: 0);
240 break;
241 }
242
243 return 0;
244}
245
246static const struct snd_kcontrol_new midas_controls[] = {
247 SOC_DAPM_PIN_SWITCH("HP"),
248
249 SOC_DAPM_PIN_SWITCH("SPK"),
250 SOC_DAPM_PIN_SWITCH("RCV"),
251
252 SOC_DAPM_PIN_SWITCH("LINE"),
253 SOC_DAPM_PIN_SWITCH("HDMI"),
254
255 SOC_DAPM_PIN_SWITCH("Main Mic"),
256 SOC_DAPM_PIN_SWITCH("Sub Mic"),
257 SOC_DAPM_PIN_SWITCH("Headset Mic"),
258
259 SOC_DAPM_PIN_SWITCH("FM In"),
260};
261
262static const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
263 SND_SOC_DAPM_HP("HP", NULL),
264
265 SND_SOC_DAPM_SPK("SPK", midas_ext_spkmode),
266 SND_SOC_DAPM_SPK("RCV", NULL),
267
268 /* FIXME: toggle MAX77693 on i9300/i9305 */
269 SND_SOC_DAPM_LINE("LINE", midas_line_set),
270 SND_SOC_DAPM_LINE("HDMI", NULL),
271 SND_SOC_DAPM_LINE("FM In", midas_fm_set),
272
273 SND_SOC_DAPM_HP("Headphone", NULL),
274 SND_SOC_DAPM_MIC("Headset Mic", NULL),
275 SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
276 SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
277};
278
279static int midas_set_bias_level(struct snd_soc_card *card,
280 struct snd_soc_dapm_context *dapm,
281 enum snd_soc_bias_level level)
282{
283 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
284 dai_link: &card->dai_link[0]);
285 struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
286
287 if (dapm->dev != aif1_dai->dev)
288 return 0;
289
290 switch (level) {
291 case SND_SOC_BIAS_STANDBY:
292 return midas_stop_fll1(rtd);
293 case SND_SOC_BIAS_PREPARE:
294 return midas_start_fll1(rtd, rate: 0);
295 default:
296 break;
297 }
298
299 return 0;
300}
301
302static int midas_late_probe(struct snd_soc_card *card)
303{
304 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
305 dai_link: &card->dai_link[0]);
306 struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
307 struct midas_priv *priv = snd_soc_card_get_drvdata(card);
308 int ret;
309
310 /* Use MCLK2 as SYSCLK for boot */
311 ret = snd_soc_dai_set_sysclk(dai: aif1_dai, WM8994_SYSCLK_MCLK2, MCLK2_RATE,
312 SND_SOC_CLOCK_IN);
313 if (ret < 0) {
314 dev_err(aif1_dai->dev, "Failed to switch to MCLK2: %d\n", ret);
315 return ret;
316 }
317
318 ret = snd_soc_card_jack_new_pins(card, id: "Headset",
319 type: SND_JACK_HEADSET | SND_JACK_MECHANICAL |
320 SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
321 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
322 jack: &priv->headset_jack,
323 pins: headset_jack_pins,
324 ARRAY_SIZE(headset_jack_pins));
325 if (ret)
326 return ret;
327
328 wm8958_mic_detect(component: aif1_dai->component, jack: &priv->headset_jack,
329 NULL, NULL, NULL, NULL);
330 return 0;
331}
332
333static struct snd_soc_dai_driver midas_ext_dai[] = {
334 {
335 .name = "Voice call",
336 .playback = {
337 .channels_min = 1,
338 .channels_max = 2,
339 .rate_min = 8000,
340 .rate_max = 16000,
341 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
342 .formats = SNDRV_PCM_FMTBIT_S16_LE,
343 },
344 .capture = {
345 .channels_min = 1,
346 .channels_max = 2,
347 .rate_min = 8000,
348 .rate_max = 16000,
349 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
350 .formats = SNDRV_PCM_FMTBIT_S16_LE,
351 },
352 },
353 {
354 .name = "Bluetooth",
355 .playback = {
356 .channels_min = 1,
357 .channels_max = 2,
358 .rate_min = 8000,
359 .rate_max = 16000,
360 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
361 .formats = SNDRV_PCM_FMTBIT_S16_LE,
362 },
363 .capture = {
364 .channels_min = 1,
365 .channels_max = 2,
366 .rate_min = 8000,
367 .rate_max = 16000,
368 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
369 .formats = SNDRV_PCM_FMTBIT_S16_LE,
370 },
371 },
372};
373
374static const struct snd_soc_component_driver midas_component = {
375 .name = "midas-audio",
376};
377
378SND_SOC_DAILINK_DEFS(wm1811_hifi,
379 DAILINK_COMP_ARRAY(COMP_EMPTY()),
380 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
381 DAILINK_COMP_ARRAY(COMP_EMPTY()));
382
383SND_SOC_DAILINK_DEFS(wm1811_voice,
384 DAILINK_COMP_ARRAY(COMP_EMPTY()),
385 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif2")),
386 DAILINK_COMP_ARRAY(COMP_EMPTY()));
387
388SND_SOC_DAILINK_DEFS(wm1811_bt,
389 DAILINK_COMP_ARRAY(COMP_EMPTY()),
390 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif3")),
391 DAILINK_COMP_ARRAY(COMP_EMPTY()));
392
393static struct snd_soc_dai_link midas_dai[] = {
394 {
395 .name = "WM8994 AIF1",
396 .stream_name = "HiFi Primary",
397 .ops = &midas_aif1_ops,
398 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
399 SND_SOC_DAIFMT_CBM_CFM,
400 SND_SOC_DAILINK_REG(wm1811_hifi),
401 }, {
402 .name = "WM1811 Voice",
403 .stream_name = "Voice call",
404 .ignore_suspend = 1,
405 SND_SOC_DAILINK_REG(wm1811_voice),
406 }, {
407 .name = "WM1811 BT",
408 .stream_name = "Bluetooth",
409 .ignore_suspend = 1,
410 SND_SOC_DAILINK_REG(wm1811_bt),
411 },
412};
413
414static struct snd_soc_card midas_card = {
415 .name = "Midas WM1811",
416 .owner = THIS_MODULE,
417
418 .dai_link = midas_dai,
419 .num_links = ARRAY_SIZE(midas_dai),
420 .controls = midas_controls,
421 .num_controls = ARRAY_SIZE(midas_controls),
422 .dapm_widgets = midas_dapm_widgets,
423 .num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets),
424
425 .set_bias_level = midas_set_bias_level,
426 .late_probe = midas_late_probe,
427};
428
429static int midas_probe(struct platform_device *pdev)
430{
431 struct device_node *cpu_dai_node = NULL, *codec_dai_node = NULL;
432 struct device_node *cpu = NULL, *codec = NULL;
433 struct snd_soc_card *card = &midas_card;
434 struct device *dev = &pdev->dev;
435 static struct snd_soc_dai_link *dai_link;
436 struct midas_priv *priv;
437 int ret, i;
438
439 priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL);
440 if (!priv)
441 return -ENOMEM;
442
443 snd_soc_card_set_drvdata(card, data: priv);
444 card->dev = dev;
445
446 priv->reg_mic_bias = devm_regulator_get(dev, id: "mic-bias");
447 if (IS_ERR(ptr: priv->reg_mic_bias)) {
448 dev_err(dev, "Failed to get mic bias regulator\n");
449 return PTR_ERR(ptr: priv->reg_mic_bias);
450 }
451
452 priv->reg_submic_bias = devm_regulator_get(dev, id: "submic-bias");
453 if (IS_ERR(ptr: priv->reg_submic_bias)) {
454 dev_err(dev, "Failed to get submic bias regulator\n");
455 return PTR_ERR(ptr: priv->reg_submic_bias);
456 }
457
458 priv->gpio_fm_sel = devm_gpiod_get_optional(dev, con_id: "fm-sel", flags: GPIOD_OUT_HIGH);
459 if (IS_ERR(ptr: priv->gpio_fm_sel)) {
460 dev_err(dev, "Failed to get FM selection GPIO\n");
461 return PTR_ERR(ptr: priv->gpio_fm_sel);
462 }
463
464 priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, con_id: "lineout-sel",
465 flags: GPIOD_OUT_HIGH);
466 if (IS_ERR(ptr: priv->gpio_lineout_sel)) {
467 dev_err(dev, "Failed to get line out selection GPIO\n");
468 return PTR_ERR(ptr: priv->gpio_lineout_sel);
469 }
470
471 ret = snd_soc_of_parse_card_name(card, propname: "model");
472 if (ret < 0) {
473 dev_err(dev, "Card name is not specified\n");
474 return ret;
475 }
476
477 ret = snd_soc_of_parse_audio_routing(card, propname: "audio-routing");
478 if (ret < 0) {
479 /* Backwards compatible way */
480 ret = snd_soc_of_parse_audio_routing(card, propname: "samsung,audio-routing");
481 if (ret < 0) {
482 dev_err(dev, "Audio routing invalid/unspecified\n");
483 return ret;
484 }
485 }
486
487 cpu = of_get_child_by_name(node: dev->of_node, name: "cpu");
488 if (!cpu)
489 return -EINVAL;
490
491 codec = of_get_child_by_name(node: dev->of_node, name: "codec");
492 if (!codec) {
493 of_node_put(node: cpu);
494 return -EINVAL;
495 }
496
497 cpu_dai_node = of_parse_phandle(np: cpu, phandle_name: "sound-dai", index: 0);
498 of_node_put(node: cpu);
499 if (!cpu_dai_node) {
500 dev_err(dev, "parsing cpu/sound-dai failed\n");
501 of_node_put(node: codec);
502 return -EINVAL;
503 }
504
505 codec_dai_node = of_parse_phandle(np: codec, phandle_name: "sound-dai", index: 0);
506 of_node_put(node: codec);
507 if (!codec_dai_node) {
508 dev_err(dev, "audio-codec property invalid/missing\n");
509 ret = -EINVAL;
510 goto put_cpu_dai_node;
511 }
512
513 for_each_card_prelinks(card, i, dai_link) {
514 dai_link->codecs->of_node = codec_dai_node;
515 dai_link->cpus->of_node = cpu_dai_node;
516 dai_link->platforms->of_node = cpu_dai_node;
517 }
518
519 ret = devm_snd_soc_register_component(dev, component_driver: &midas_component,
520 dai_drv: midas_ext_dai, ARRAY_SIZE(midas_ext_dai));
521 if (ret < 0) {
522 dev_err(dev, "Failed to register component: %d\n", ret);
523 goto put_codec_dai_node;
524 }
525
526 ret = devm_snd_soc_register_card(dev, card);
527 if (ret < 0) {
528 dev_err(dev, "Failed to register card: %d\n", ret);
529 goto put_codec_dai_node;
530 }
531
532 return 0;
533
534put_codec_dai_node:
535 of_node_put(node: codec_dai_node);
536put_cpu_dai_node:
537 of_node_put(node: cpu_dai_node);
538 return ret;
539}
540
541static const struct of_device_id midas_of_match[] = {
542 { .compatible = "samsung,midas-audio" },
543 { },
544};
545MODULE_DEVICE_TABLE(of, midas_of_match);
546
547static struct platform_driver midas_driver = {
548 .driver = {
549 .name = "midas-audio",
550 .of_match_table = midas_of_match,
551 .pm = &snd_soc_pm_ops,
552 },
553 .probe = midas_probe,
554};
555module_platform_driver(midas_driver);
556
557MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
558MODULE_DESCRIPTION("ASoC support for Midas");
559MODULE_LICENSE("GPL v2");
560

source code of linux/sound/soc/samsung/midas_wm1811.c