xref: /linux/sound/soc/samsung/midas_wm1811.c (revision d2a4a07190f42e4f82805daf58e708400b703f1c)
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 
29 struct 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 
39 static 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 
50 static 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(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(aif1_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
78 				  MCLK1_RATE, 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(aif1_dai, WM8994_SYSCLK_FLL1,
86 				     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(cpu_dai, SAMSUNG_I2S_OPCLK, 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 
102 static 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(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(aif1_dai, WM8994_FLL1, 0, 0, 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 
127 static 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 = snd_soc_substream_to_rtd(substream);
131 	unsigned int pll_out;
132 
133 	/* AIF1CLK should be at least 3MHz for "optimal performance" */
134 	if (params_rate(params) == 8000 || params_rate(params) == 11025)
135 		pll_out = params_rate(params) * 512;
136 	else
137 		pll_out = params_rate(params) * 256;
138 
139 	return midas_start_fll1(rtd, pll_out);
140 }
141 
142 static 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  */
150 static 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(w->dapm);
154 	int ret = 0;
155 
156 	switch (event) {
157 	case SND_SOC_DAPM_PRE_PMU:
158 		ret = snd_soc_component_update_bits(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(codec, WM8994_SPKOUT_MIXERS,
164 				  WM8994_SPKMIXR_TO_SPKOUTL_MASK,
165 				  0);
166 		break;
167 	}
168 
169 	return ret;
170 }
171 
172 static 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(priv->reg_mic_bias);
181 	case SND_SOC_DAPM_POST_PMD:
182 		return regulator_disable(priv->reg_mic_bias);
183 	}
184 
185 	return 0;
186 }
187 
188 static 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(priv->reg_submic_bias);
197 	case SND_SOC_DAPM_POST_PMD:
198 		return regulator_disable(priv->reg_submic_bias);
199 	}
200 
201 	return 0;
202 }
203 
204 static 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(priv->gpio_fm_sel, 1);
216 		break;
217 	case SND_SOC_DAPM_POST_PMD:
218 		gpiod_set_value_cansleep(priv->gpio_fm_sel, 0);
219 		break;
220 	}
221 
222 	return 0;
223 }
224 
225 static 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(priv->gpio_lineout_sel, 1);
237 		break;
238 	case SND_SOC_DAPM_POST_PMD:
239 		gpiod_set_value_cansleep(priv->gpio_lineout_sel, 0);
240 		break;
241 	}
242 
243 	return 0;
244 }
245 
246 static 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 
262 static 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 
279 static 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 						  &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, 0);
295 	default:
296 		break;
297 	}
298 
299 	return 0;
300 }
301 
302 static int midas_late_probe(struct snd_soc_card *card)
303 {
304 	struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
305 							&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(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, "Headset",
319 					 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 					 &priv->headset_jack,
323 					 headset_jack_pins,
324 					 ARRAY_SIZE(headset_jack_pins));
325 	if (ret)
326 		return ret;
327 
328 	wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
329 			  NULL, NULL, NULL, NULL);
330 	return 0;
331 }
332 
333 static 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 
374 static const struct snd_soc_component_driver midas_component = {
375 	.name	= "midas-audio",
376 };
377 
378 SND_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 
383 SND_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 
388 SND_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 
393 static 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 
414 static 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 
429 static 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, sizeof(*priv), GFP_KERNEL);
440 	if (!priv)
441 		return -ENOMEM;
442 
443 	snd_soc_card_set_drvdata(card, priv);
444 	card->dev = dev;
445 
446 	priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias");
447 	if (IS_ERR(priv->reg_mic_bias)) {
448 		dev_err(dev, "Failed to get mic bias regulator\n");
449 		return PTR_ERR(priv->reg_mic_bias);
450 	}
451 
452 	priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias");
453 	if (IS_ERR(priv->reg_submic_bias)) {
454 		dev_err(dev, "Failed to get submic bias regulator\n");
455 		return PTR_ERR(priv->reg_submic_bias);
456 	}
457 
458 	priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH);
459 	if (IS_ERR(priv->gpio_fm_sel)) {
460 		dev_err(dev, "Failed to get FM selection GPIO\n");
461 		return PTR_ERR(priv->gpio_fm_sel);
462 	}
463 
464 	priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel",
465 						    GPIOD_OUT_HIGH);
466 	if (IS_ERR(priv->gpio_lineout_sel)) {
467 		dev_err(dev, "Failed to get line out selection GPIO\n");
468 		return PTR_ERR(priv->gpio_lineout_sel);
469 	}
470 
471 	ret = snd_soc_of_parse_card_name(card, "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, "audio-routing");
478 	if (ret < 0) {
479 		/* Backwards compatible way */
480 		ret = snd_soc_of_parse_audio_routing(card, "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(dev->of_node, "cpu");
488 	if (!cpu)
489 		return -EINVAL;
490 
491 	codec = of_get_child_by_name(dev->of_node, "codec");
492 	if (!codec) {
493 		of_node_put(cpu);
494 		return -EINVAL;
495 	}
496 
497 	cpu_dai_node = of_parse_phandle(cpu, "sound-dai", 0);
498 	of_node_put(cpu);
499 	if (!cpu_dai_node) {
500 		dev_err(dev, "parsing cpu/sound-dai failed\n");
501 		of_node_put(codec);
502 		return -EINVAL;
503 	}
504 
505 	codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
506 	of_node_put(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, &midas_component,
520 			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 
534 put_codec_dai_node:
535 	of_node_put(codec_dai_node);
536 put_cpu_dai_node:
537 	of_node_put(cpu_dai_node);
538 	return ret;
539 }
540 
541 static const struct of_device_id midas_of_match[] = {
542 	{ .compatible = "samsung,midas-audio" },
543 	{ },
544 };
545 MODULE_DEVICE_TABLE(of, midas_of_match);
546 
547 static 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 };
555 module_platform_driver(midas_driver);
556 
557 MODULE_AUTHOR("Simon Shields <simon@lineageos.org>");
558 MODULE_DESCRIPTION("ASoC support for Midas");
559 MODULE_LICENSE("GPL v2");
560