174462Salfred// SPDX-License-Identifier: GPL-2.0+
274462Salfred//
31839Swollman// Midas audio support
41839Swollman//
51839Swollman// Copyright (C) 2018 Simon Shields <simon@lineageos.org>
61839Swollman// Copyright (C) 2020 Samsung Electronics Co., Ltd.
71839Swollman
81839Swollman#include <linux/clk.h>
91839Swollman#include <linux/gpio/consumer.h>
108858Srgrimes#include <linux/mfd/wm8994/registers.h>
111839Swollman#include <linux/module.h>
1213771Smpp#include <linux/of.h>
131839Swollman#include <linux/regulator/consumer.h>
148858Srgrimes#include <sound/jack.h>
151839Swollman#include <sound/soc.h>
161839Swollman#include <sound/soc-dapm.h>
171839Swollman
188858Srgrimes#include "i2s.h"
191839Swollman#include "../codecs/wm8994.h"
201839Swollman
211839Swollman/*
228858Srgrimes * The MCLK1 clock source is XCLKOUT with its mux set to the external fixed rate
231839Swollman * oscillator (XXTI).
241839Swollman */
251839Swollman#define MCLK1_RATE 24000000U
268858Srgrimes#define MCLK2_RATE 32768U
271839Swollman#define DEFAULT_FLL1_RATE 11289600U
281839Swollman
291839Swollmanstruct midas_priv {
301903Swollman	struct regulator *reg_mic_bias;
3174462Salfred	struct regulator *reg_submic_bias;
321903Swollman	struct gpio_desc *gpio_fm_sel;
3350473Speter	struct gpio_desc *gpio_lineout_sel;
341839Swollman	unsigned int fll1_rate;
351839Swollman
361839Swollman	struct snd_soc_jack headset_jack;
371839Swollman};
381839Swollman
391839Swollmanstatic struct snd_soc_jack_pin headset_jack_pins[] = {
401839Swollman	{
411839Swollman		.pin = "Headphone",
421903Swollman		.mask = SND_JACK_HEADPHONE,
431903Swollman	},
4474462Salfred	{
451903Swollman		.pin = "Headset Mic",
4674462Salfred		.mask = SND_JACK_MICROPHONE,
4726211Swpaul	},
481839Swollman};
491839Swollman
5074462Salfredstatic int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
511839Swollman{
5274462Salfred	struct snd_soc_card *card = rtd->card;
531839Swollman	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
5474462Salfred	struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
5574462Salfred	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
5674462Salfred	int ret;
5774462Salfred
5874462Salfred	if (!rate)
5974462Salfred		rate = priv->fll1_rate;
6074462Salfred	/*
6174462Salfred	 * If no new rate is requested, set FLL1 to a sane default for jack
6274462Salfred	 * detection.
6374462Salfred	 */
6474462Salfred	if (!rate)
6574462Salfred		rate = DEFAULT_FLL1_RATE;
661839Swollman
671839Swollman	if (rate != priv->fll1_rate && priv->fll1_rate) {
681839Swollman		/* while reconfiguring, switch to MCLK2 for SYSCLK */
691839Swollman		ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
701839Swollman					     MCLK2_RATE, SND_SOC_CLOCK_IN);
711839Swollman		if (ret < 0) {
721839Swollman			dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret);
7313771Smpp			return ret;
741839Swollman		}
751839Swollman	}
7674462Salfred
7774462Salfred	ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
781839Swollman				  MCLK1_RATE, rate);
791839Swollman	if (ret < 0) {
8021059Speter		dev_err(card->dev, "Failed to set FLL1 rate: %d\n", ret);
8121059Speter		return ret;
821839Swollman	}
831839Swollman	priv->fll1_rate = rate;
841839Swollman
851839Swollman	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_FLL1,
861839Swollman				     priv->fll1_rate, SND_SOC_CLOCK_IN);
871839Swollman	if (ret < 0) {
881839Swollman		dev_err(card->dev, "Failed to set SYSCLK source: %d\n", ret);
891839Swollman		return ret;
901839Swollman	}
911839Swollman
921839Swollman	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, 0,
9374462Salfred				     SAMSUNG_I2S_OPCLK_PCLK);
941839Swollman	if (ret < 0) {
951839Swollman		dev_err(card->dev, "Failed to set OPCLK source: %d\n", ret);
9621059Speter		return ret;
971839Swollman	}
981839Swollman
9921059Speter	return 0;
10021059Speter}
10174462Salfred
10221059Speterstatic int midas_stop_fll1(struct snd_soc_pcm_runtime *rtd)
10321059Speter{
10421059Speter	struct snd_soc_card *card = rtd->card;
10521059Speter	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
10621059Speter	struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
10721059Speter	int ret;
10821059Speter
10921059Speter	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
11021059Speter				     MCLK2_RATE, SND_SOC_CLOCK_IN);
11121059Speter	if (ret < 0) {
11221059Speter		dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret);
11321059Speter		return ret;
11421059Speter	}
11574462Salfred
1161839Swollman	ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, 0, 0, 0);
11774462Salfred	if (ret < 0) {
11874462Salfred		dev_err(card->dev, "Unable to stop FLL1: %d\n", ret);
11974462Salfred		return ret;
1201839Swollman	}
1211839Swollman
1221839Swollman	priv->fll1_rate = 0;
1231839Swollman
12474462Salfred	return 0;
12574462Salfred}
12674462Salfred
12774462Salfredstatic int midas_aif1_hw_params(struct snd_pcm_substream *substream,
12874462Salfred				struct snd_pcm_hw_params *params)
12974462Salfred{
13074462Salfred	struct snd_soc_pcm_runtime *rtd	= substream->private_data;
13174462Salfred	unsigned int pll_out;
13274462Salfred
13374462Salfred	/* AIF1CLK should be at least 3MHz for "optimal performance" */
13474462Salfred	if (params_rate(params) == 8000 || params_rate(params) == 11025)
13574462Salfred		pll_out = params_rate(params) * 512;
13674462Salfred	else
13774462Salfred		pll_out = params_rate(params) * 256;
13874462Salfred
13974462Salfred	return midas_start_fll1(rtd, pll_out);
14074462Salfred}
14174462Salfred
14274462Salfredstatic const struct snd_soc_ops midas_aif1_ops = {
14374462Salfred	.hw_params = midas_aif1_hw_params,
14474462Salfred};
14574462Salfred
1461839Swollman/*
1471839Swollman * We only have a single external speaker, so mix stereo data
1481839Swollman * to a single mono stream.
1491839Swollman */
1501839Swollmanstatic int midas_ext_spkmode(struct snd_soc_dapm_widget *w,
1511839Swollman			     struct snd_kcontrol *kcontrol, int event)
1521839Swollman{
1531839Swollman	struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
1541839Swollman	int ret = 0;
1551839Swollman
15674462Salfred	switch (event) {
1571839Swollman	case SND_SOC_DAPM_PRE_PMU:
1581839Swollman		ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS,
1591839Swollman				  WM8994_SPKMIXR_TO_SPKOUTL_MASK,
1601839Swollman				  WM8994_SPKMIXR_TO_SPKOUTL);
1611839Swollman		break;
1621839Swollman	case SND_SOC_DAPM_POST_PMD:
16374462Salfred		ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS,
16474462Salfred				  WM8994_SPKMIXR_TO_SPKOUTL_MASK,
16574462Salfred				  0);
16674462Salfred		break;
16774462Salfred	}
16874462Salfred
1691839Swollman	return ret;
1701839Swollman}
1711839Swollman
1721839Swollmanstatic int midas_mic_bias(struct snd_soc_dapm_widget *w,
1731839Swollman			  struct snd_kcontrol *kcontrol, int event)
1741839Swollman{
1751839Swollman	struct snd_soc_card *card = w->dapm->card;
1761839Swollman	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
1771839Swollman
1781839Swollman	switch (event) {
1791839Swollman	case SND_SOC_DAPM_PRE_PMU:
1801839Swollman		return regulator_enable(priv->reg_mic_bias);
1811839Swollman	case SND_SOC_DAPM_POST_PMD:
1821839Swollman		return regulator_disable(priv->reg_mic_bias);
1831839Swollman	}
1841839Swollman
1851839Swollman	return 0;
1861839Swollman}
1871839Swollman
1881839Swollmanstatic int midas_submic_bias(struct snd_soc_dapm_widget *w,
1891839Swollman			     struct snd_kcontrol *kcontrol, int event)
1901839Swollman{
1911839Swollman	struct snd_soc_card *card = w->dapm->card;
1921839Swollman	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
1931839Swollman
1941839Swollman	switch (event) {
1951839Swollman	case SND_SOC_DAPM_PRE_PMU:
1961839Swollman		return regulator_enable(priv->reg_submic_bias);
1971839Swollman	case SND_SOC_DAPM_POST_PMD:
1981839Swollman		return regulator_disable(priv->reg_submic_bias);
1991839Swollman	}
2001839Swollman
2011839Swollman	return 0;
2021839Swollman}
2031839Swollman
2041839Swollmanstatic int midas_fm_set(struct snd_soc_dapm_widget *w,
2051839Swollman			struct snd_kcontrol *kcontrol, int event)
2061839Swollman{
2071839Swollman	struct snd_soc_card *card = w->dapm->card;
20874462Salfred	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
2091839Swollman
21074462Salfred	if (!priv->gpio_fm_sel)
21174462Salfred		return 0;
21274462Salfred
21374462Salfred	switch (event) {
21474462Salfred	case SND_SOC_DAPM_PRE_PMU:
21574462Salfred		gpiod_set_value_cansleep(priv->gpio_fm_sel, 1);
21674462Salfred		break;
21774462Salfred	case SND_SOC_DAPM_POST_PMD:
21874462Salfred		gpiod_set_value_cansleep(priv->gpio_fm_sel, 0);
21974462Salfred		break;
22074462Salfred	}
22174462Salfred
22274462Salfred	return 0;
22374462Salfred}
22474462Salfred
22574462Salfredstatic int midas_line_set(struct snd_soc_dapm_widget *w,
2261839Swollman			  struct snd_kcontrol *kcontrol, int event)
22774462Salfred{
2281839Swollman	struct snd_soc_card *card = w->dapm->card;
2291839Swollman	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
2301839Swollman
2311839Swollman	if (!priv->gpio_lineout_sel)
2321839Swollman		return 0;
2331839Swollman
2341839Swollman	switch (event) {
2351839Swollman	case SND_SOC_DAPM_PRE_PMU:
2361839Swollman		gpiod_set_value_cansleep(priv->gpio_lineout_sel, 1);
2371839Swollman		break;
2381839Swollman	case SND_SOC_DAPM_POST_PMD:
2391839Swollman		gpiod_set_value_cansleep(priv->gpio_lineout_sel, 0);
2401839Swollman		break;
2411839Swollman	}
24213771Smpp
2431839Swollman	return 0;
2441839Swollman}
2451839Swollman
2461839Swollmanstatic const struct snd_kcontrol_new midas_controls[] = {
24774462Salfred	SOC_DAPM_PIN_SWITCH("HP"),
24874462Salfred
24974462Salfred	SOC_DAPM_PIN_SWITCH("SPK"),
25074462Salfred	SOC_DAPM_PIN_SWITCH("RCV"),
2511839Swollman
2521839Swollman	SOC_DAPM_PIN_SWITCH("LINE"),
2531839Swollman	SOC_DAPM_PIN_SWITCH("HDMI"),
2541839Swollman
2551839Swollman	SOC_DAPM_PIN_SWITCH("Main Mic"),
25674462Salfred	SOC_DAPM_PIN_SWITCH("Sub Mic"),
2571839Swollman	SOC_DAPM_PIN_SWITCH("Headset Mic"),
2581839Swollman
2591839Swollman	SOC_DAPM_PIN_SWITCH("FM In"),
2608858Srgrimes};
2611839Swollman
2621839Swollmanstatic const struct snd_soc_dapm_widget midas_dapm_widgets[] = {
2631839Swollman	SND_SOC_DAPM_HP("HP", NULL),
2641839Swollman
26574462Salfred	SND_SOC_DAPM_SPK("SPK", midas_ext_spkmode),
26674462Salfred	SND_SOC_DAPM_SPK("RCV", NULL),
2671839Swollman
26874462Salfred	/* FIXME: toggle MAX77693 on i9300/i9305 */
26974462Salfred	SND_SOC_DAPM_LINE("LINE", midas_line_set),
27074462Salfred	SND_SOC_DAPM_LINE("HDMI", NULL),
27174462Salfred	SND_SOC_DAPM_LINE("FM In", midas_fm_set),
27274462Salfred
2731839Swollman	SND_SOC_DAPM_HP("Headphone", NULL),
2741903Swollman	SND_SOC_DAPM_MIC("Headset Mic", NULL),
27574462Salfred	SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias),
27674462Salfred	SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias),
27774462Salfred};
27874462Salfred
27974462Salfredstatic int midas_set_bias_level(struct snd_soc_card *card,
28074462Salfred				struct snd_soc_dapm_context *dapm,
28174462Salfred				enum snd_soc_bias_level level)
28274462Salfred{
28374462Salfred	struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
2841839Swollman						  &card->dai_link[0]);
2851839Swollman	struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
28674462Salfred
28774462Salfred	if (dapm->dev != aif1_dai->dev)
2881839Swollman		return 0;
28974462Salfred
29074462Salfred	switch (level) {
29174462Salfred	case SND_SOC_BIAS_STANDBY:
29274462Salfred		return midas_stop_fll1(rtd);
29374462Salfred	case SND_SOC_BIAS_PREPARE:
29474462Salfred		return midas_start_fll1(rtd, 0);
29574462Salfred	default:
29674462Salfred		break;
29774462Salfred	}
29874462Salfred
29974462Salfred	return 0;
3001839Swollman}
3011839Swollman
3021839Swollmanstatic int midas_late_probe(struct snd_soc_card *card)
30374462Salfred{
30474462Salfred	struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card,
3051839Swollman							&card->dai_link[0]);
30674462Salfred	struct snd_soc_dai *aif1_dai = snd_soc_rtd_to_codec(rtd, 0);
30774462Salfred	struct midas_priv *priv = snd_soc_card_get_drvdata(card);
30874462Salfred	int ret;
30974462Salfred
31074462Salfred	/* Use MCLK2 as SYSCLK for boot */
31174462Salfred	ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, MCLK2_RATE,
31274462Salfred				     SND_SOC_CLOCK_IN);
31374462Salfred	if (ret < 0) {
3141839Swollman		dev_err(aif1_dai->dev, "Failed to switch to MCLK2: %d\n", ret);
31574462Salfred		return ret;
31674462Salfred	}
31774462Salfred
3181903Swollman	ret = snd_soc_card_jack_new_pins(card, "Headset",
31974462Salfred					 SND_JACK_HEADSET | SND_JACK_MECHANICAL |
32074462Salfred					 SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
32174462Salfred					 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
3221839Swollman					 &priv->headset_jack,
32374462Salfred					 headset_jack_pins,
32474462Salfred					 ARRAY_SIZE(headset_jack_pins));
32574462Salfred	if (ret)
32674462Salfred		return ret;
32774462Salfred
32874462Salfred	wm8958_mic_detect(aif1_dai->component, &priv->headset_jack,
32974462Salfred			  NULL, NULL, NULL, NULL);
3301839Swollman	return 0;
3311839Swollman}
33274462Salfred
33374462Salfredstatic struct snd_soc_dai_driver midas_ext_dai[] = {
33474462Salfred	{
33574462Salfred		.name = "Voice call",
33674462Salfred		.playback = {
33774462Salfred			.channels_min = 1,
33874462Salfred			.channels_max = 2,
33974462Salfred			.rate_min = 8000,
34074462Salfred			.rate_max = 16000,
34174462Salfred			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
34274462Salfred			.formats = SNDRV_PCM_FMTBIT_S16_LE,
34374462Salfred		},
34474462Salfred		.capture = {
34574462Salfred			.channels_min = 1,
3461903Swollman			.channels_max = 2,
3471839Swollman			.rate_min = 8000,
34874462Salfred			.rate_max = 16000,
34974462Salfred			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
35074462Salfred			.formats = SNDRV_PCM_FMTBIT_S16_LE,
35174462Salfred		},
35274462Salfred	},
35374462Salfred	{
35474462Salfred		.name = "Bluetooth",
35574462Salfred		.playback = {
35674462Salfred			.channels_min = 1,
35774462Salfred			.channels_max = 2,
35874462Salfred			.rate_min = 8000,
35974462Salfred			.rate_max = 16000,
36074462Salfred			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
36174462Salfred			.formats = SNDRV_PCM_FMTBIT_S16_LE,
36274462Salfred		},
36374462Salfred		.capture = {
36426211Swpaul			.channels_min = 1,
36574462Salfred			.channels_max = 2,
36626211Swpaul			.rate_min = 8000,
36774462Salfred			.rate_max = 16000,
36826211Swpaul			.rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000),
36974462Salfred			.formats = SNDRV_PCM_FMTBIT_S16_LE,
37074462Salfred		},
37126211Swpaul	},
37226211Swpaul};
37326211Swpaul
37426211Swpaulstatic const struct snd_soc_component_driver midas_component = {
3751839Swollman	.name	= "midas-audio",
3761839Swollman};
3771903Swollman
37874462SalfredSND_SOC_DAILINK_DEFS(wm1811_hifi,
37974462Salfred	DAILINK_COMP_ARRAY(COMP_EMPTY()),
3801903Swollman	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
3811839Swollman	DAILINK_COMP_ARRAY(COMP_EMPTY()));
3821839Swollman
3831839SwollmanSND_SOC_DAILINK_DEFS(wm1811_voice,
3848858Srgrimes	DAILINK_COMP_ARRAY(COMP_EMPTY()),
3851903Swollman	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif2")),
3861903Swollman	DAILINK_COMP_ARRAY(COMP_EMPTY()));
3871903Swollman
3881903SwollmanSND_SOC_DAILINK_DEFS(wm1811_bt,
3891839Swollman	DAILINK_COMP_ARRAY(COMP_EMPTY()),
3901839Swollman	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif3")),
3911839Swollman	DAILINK_COMP_ARRAY(COMP_EMPTY()));
3921839Swollman
3931903Swollmanstatic struct snd_soc_dai_link midas_dai[] = {
39474462Salfred	{
39574462Salfred		.name = "WM8994 AIF1",
3961903Swollman		.stream_name = "HiFi Primary",
3971839Swollman		.ops = &midas_aif1_ops,
3981903Swollman		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
3998858Srgrimes			SND_SOC_DAIFMT_CBM_CFM,
4001839Swollman		SND_SOC_DAILINK_REG(wm1811_hifi),
4011839Swollman	}, {
4021839Swollman		.name = "WM1811 Voice",
4031839Swollman		.stream_name = "Voice call",
4041839Swollman		.ignore_suspend = 1,
4051839Swollman		SND_SOC_DAILINK_REG(wm1811_voice),
4061839Swollman	}, {
40774462Salfred		.name = "WM1811 BT",
40874462Salfred		.stream_name = "Bluetooth",
40974462Salfred		.ignore_suspend = 1,
41074462Salfred		SND_SOC_DAILINK_REG(wm1811_bt),
41174462Salfred	},
41274462Salfred};
4131839Swollman
41474462Salfredstatic struct snd_soc_card midas_card = {
4151839Swollman	.name = "Midas WM1811",
41674462Salfred	.owner = THIS_MODULE,
41774462Salfred
41874462Salfred	.dai_link = midas_dai,
41974462Salfred	.num_links = ARRAY_SIZE(midas_dai),
42074462Salfred	.controls = midas_controls,
42174462Salfred	.num_controls = ARRAY_SIZE(midas_controls),
42274462Salfred	.dapm_widgets = midas_dapm_widgets,
42374462Salfred	.num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets),
42474462Salfred
42574462Salfred	.set_bias_level = midas_set_bias_level,
42674462Salfred	.late_probe = midas_late_probe,
42774462Salfred};
42874462Salfred
42974462Salfredstatic int midas_probe(struct platform_device *pdev)
43074462Salfred{
43174462Salfred	struct device_node *cpu_dai_node = NULL, *codec_dai_node = NULL;
43274462Salfred	struct device_node *cpu = NULL, *codec = NULL;
43374462Salfred	struct snd_soc_card *card = &midas_card;
43474462Salfred	struct device *dev = &pdev->dev;
4351839Swollman	static struct snd_soc_dai_link *dai_link;
43674462Salfred	struct midas_priv *priv;
43774462Salfred	int ret, i;
43874462Salfred
43974462Salfred	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
44074462Salfred	if (!priv)
44174462Salfred		return -ENOMEM;
44274462Salfred
44374462Salfred	snd_soc_card_set_drvdata(card, priv);
44474462Salfred	card->dev = dev;
44574462Salfred
44674462Salfred	priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias");
44774462Salfred	if (IS_ERR(priv->reg_mic_bias)) {
44874462Salfred		dev_err(dev, "Failed to get mic bias regulator\n");
44974462Salfred		return PTR_ERR(priv->reg_mic_bias);
45074462Salfred	}
45174462Salfred
45274462Salfred	priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias");
45374462Salfred	if (IS_ERR(priv->reg_submic_bias)) {
45474462Salfred		dev_err(dev, "Failed to get submic bias regulator\n");
45574462Salfred		return PTR_ERR(priv->reg_submic_bias);
45674462Salfred	}
45774462Salfred
45874462Salfred	priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH);
45974462Salfred	if (IS_ERR(priv->gpio_fm_sel)) {
46074462Salfred		dev_err(dev, "Failed to get FM selection GPIO\n");
46174462Salfred		return PTR_ERR(priv->gpio_fm_sel);
46274462Salfred	}
46374462Salfred
46474462Salfred	priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel",
46574462Salfred						    GPIOD_OUT_HIGH);
46674462Salfred	if (IS_ERR(priv->gpio_lineout_sel)) {
46774462Salfred		dev_err(dev, "Failed to get line out selection GPIO\n");
46874462Salfred		return PTR_ERR(priv->gpio_lineout_sel);
46974462Salfred	}
47074462Salfred
47174462Salfred	ret = snd_soc_of_parse_card_name(card, "model");
47274462Salfred	if (ret < 0) {
47374462Salfred		dev_err(dev, "Card name is not specified\n");
47474462Salfred		return ret;
47574462Salfred	}
47674462Salfred
47774462Salfred	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
47874462Salfred	if (ret < 0) {
4791839Swollman		/* Backwards compatible way */
48074462Salfred		ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing");
48174462Salfred		if (ret < 0) {
48274462Salfred			dev_err(dev, "Audio routing invalid/unspecified\n");
48374462Salfred			return ret;
48474462Salfred		}
48574462Salfred	}
48674462Salfred
48774462Salfred	cpu = of_get_child_by_name(dev->of_node, "cpu");
48874462Salfred	if (!cpu)
48974462Salfred		return -EINVAL;
49074462Salfred
49174462Salfred	codec = of_get_child_by_name(dev->of_node, "codec");
49274462Salfred	if (!codec) {
49374462Salfred		of_node_put(cpu);
49474462Salfred		return -EINVAL;
49574462Salfred	}
49674462Salfred
49774462Salfred	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
534put_codec_dai_node:
535	of_node_put(codec_dai_node);
536put_cpu_dai_node:
537	of_node_put(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