xref: /linux/sound/soc/ti/rx51.c (revision df561f6688fef775baa341a0f5d960becd248b11)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f2055e14SPeter Ujfalusi /*
3f2055e14SPeter Ujfalusi  * rx51.c  --  SoC audio for Nokia RX-51
4f2055e14SPeter Ujfalusi  *
5f2055e14SPeter Ujfalusi  * Copyright (C) 2008 - 2009 Nokia Corporation
6f2055e14SPeter Ujfalusi  *
7f2055e14SPeter Ujfalusi  * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
8f2055e14SPeter Ujfalusi  *          Eduardo Valentin <eduardo.valentin@nokia.com>
9f2055e14SPeter Ujfalusi  *          Jarkko Nikula <jarkko.nikula@bitmer.com>
10f2055e14SPeter Ujfalusi  */
11f2055e14SPeter Ujfalusi 
12f2055e14SPeter Ujfalusi #include <linux/delay.h>
13f2055e14SPeter Ujfalusi #include <linux/gpio.h>
14f2055e14SPeter Ujfalusi #include <linux/platform_device.h>
15f2055e14SPeter Ujfalusi #include <linux/gpio/consumer.h>
16f2055e14SPeter Ujfalusi #include <linux/module.h>
17f2055e14SPeter Ujfalusi #include <sound/core.h>
18f2055e14SPeter Ujfalusi #include <sound/jack.h>
19f2055e14SPeter Ujfalusi #include <sound/pcm.h>
20f2055e14SPeter Ujfalusi #include <sound/soc.h>
21f2055e14SPeter Ujfalusi #include <linux/platform_data/asoc-ti-mcbsp.h>
22f2055e14SPeter Ujfalusi 
23f2055e14SPeter Ujfalusi #include <asm/mach-types.h>
24f2055e14SPeter Ujfalusi 
25f2055e14SPeter Ujfalusi #include "omap-mcbsp.h"
26f2055e14SPeter Ujfalusi 
27f2055e14SPeter Ujfalusi enum {
28f2055e14SPeter Ujfalusi 	RX51_JACK_DISABLED,
29f2055e14SPeter Ujfalusi 	RX51_JACK_TVOUT,		/* tv-out with stereo output */
30f2055e14SPeter Ujfalusi 	RX51_JACK_HP,			/* headphone: stereo output, no mic */
31f2055e14SPeter Ujfalusi 	RX51_JACK_HS,			/* headset: stereo output with mic */
32f2055e14SPeter Ujfalusi };
33f2055e14SPeter Ujfalusi 
34f2055e14SPeter Ujfalusi struct rx51_audio_pdata {
35f2055e14SPeter Ujfalusi 	struct gpio_desc *tvout_selection_gpio;
36f2055e14SPeter Ujfalusi 	struct gpio_desc *jack_detection_gpio;
37f2055e14SPeter Ujfalusi 	struct gpio_desc *eci_sw_gpio;
38f2055e14SPeter Ujfalusi 	struct gpio_desc *speaker_amp_gpio;
39f2055e14SPeter Ujfalusi };
40f2055e14SPeter Ujfalusi 
41f2055e14SPeter Ujfalusi static int rx51_spk_func;
42f2055e14SPeter Ujfalusi static int rx51_dmic_func;
43f2055e14SPeter Ujfalusi static int rx51_jack_func;
44f2055e14SPeter Ujfalusi 
45f2055e14SPeter Ujfalusi static void rx51_ext_control(struct snd_soc_dapm_context *dapm)
46f2055e14SPeter Ujfalusi {
47f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = dapm->card;
48f2055e14SPeter Ujfalusi 	struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
49f2055e14SPeter Ujfalusi 	int hp = 0, hs = 0, tvout = 0;
50f2055e14SPeter Ujfalusi 
51f2055e14SPeter Ujfalusi 	switch (rx51_jack_func) {
52f2055e14SPeter Ujfalusi 	case RX51_JACK_TVOUT:
53f2055e14SPeter Ujfalusi 		tvout = 1;
54f2055e14SPeter Ujfalusi 		hp = 1;
55f2055e14SPeter Ujfalusi 		break;
56f2055e14SPeter Ujfalusi 	case RX51_JACK_HS:
57f2055e14SPeter Ujfalusi 		hs = 1;
58*df561f66SGustavo A. R. Silva 		fallthrough;
59f2055e14SPeter Ujfalusi 	case RX51_JACK_HP:
60f2055e14SPeter Ujfalusi 		hp = 1;
61f2055e14SPeter Ujfalusi 		break;
62f2055e14SPeter Ujfalusi 	}
63f2055e14SPeter Ujfalusi 
64f2055e14SPeter Ujfalusi 	snd_soc_dapm_mutex_lock(dapm);
65f2055e14SPeter Ujfalusi 
66f2055e14SPeter Ujfalusi 	if (rx51_spk_func)
67f2055e14SPeter Ujfalusi 		snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
68f2055e14SPeter Ujfalusi 	else
69f2055e14SPeter Ujfalusi 		snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
70f2055e14SPeter Ujfalusi 	if (rx51_dmic_func)
71f2055e14SPeter Ujfalusi 		snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
72f2055e14SPeter Ujfalusi 	else
73f2055e14SPeter Ujfalusi 		snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
74f2055e14SPeter Ujfalusi 	if (hp)
75f2055e14SPeter Ujfalusi 		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
76f2055e14SPeter Ujfalusi 	else
77f2055e14SPeter Ujfalusi 		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
78f2055e14SPeter Ujfalusi 	if (hs)
79f2055e14SPeter Ujfalusi 		snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
80f2055e14SPeter Ujfalusi 	else
81f2055e14SPeter Ujfalusi 		snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
82f2055e14SPeter Ujfalusi 
83f2055e14SPeter Ujfalusi 	gpiod_set_value(pdata->tvout_selection_gpio, tvout);
84f2055e14SPeter Ujfalusi 
85f2055e14SPeter Ujfalusi 	snd_soc_dapm_sync_unlocked(dapm);
86f2055e14SPeter Ujfalusi 
87f2055e14SPeter Ujfalusi 	snd_soc_dapm_mutex_unlock(dapm);
88f2055e14SPeter Ujfalusi }
89f2055e14SPeter Ujfalusi 
90f2055e14SPeter Ujfalusi static int rx51_startup(struct snd_pcm_substream *substream)
91f2055e14SPeter Ujfalusi {
92f2055e14SPeter Ujfalusi 	struct snd_pcm_runtime *runtime = substream->runtime;
9302cde14aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
94f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = rtd->card;
95f2055e14SPeter Ujfalusi 
96f2055e14SPeter Ujfalusi 	snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
97f2055e14SPeter Ujfalusi 	rx51_ext_control(&card->dapm);
98f2055e14SPeter Ujfalusi 
99f2055e14SPeter Ujfalusi 	return 0;
100f2055e14SPeter Ujfalusi }
101f2055e14SPeter Ujfalusi 
102f2055e14SPeter Ujfalusi static int rx51_hw_params(struct snd_pcm_substream *substream,
103f2055e14SPeter Ujfalusi 	struct snd_pcm_hw_params *params)
104f2055e14SPeter Ujfalusi {
10502cde14aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1062842b871SKuninori Morimoto 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
107f2055e14SPeter Ujfalusi 
108f2055e14SPeter Ujfalusi 	/* Set the codec system clock for DAC and ADC */
109f2055e14SPeter Ujfalusi 	return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
110f2055e14SPeter Ujfalusi 				      SND_SOC_CLOCK_IN);
111f2055e14SPeter Ujfalusi }
112f2055e14SPeter Ujfalusi 
113f2055e14SPeter Ujfalusi static const struct snd_soc_ops rx51_ops = {
114f2055e14SPeter Ujfalusi 	.startup = rx51_startup,
115f2055e14SPeter Ujfalusi 	.hw_params = rx51_hw_params,
116f2055e14SPeter Ujfalusi };
117f2055e14SPeter Ujfalusi 
118f2055e14SPeter Ujfalusi static int rx51_get_spk(struct snd_kcontrol *kcontrol,
119f2055e14SPeter Ujfalusi 			struct snd_ctl_elem_value *ucontrol)
120f2055e14SPeter Ujfalusi {
121f2055e14SPeter Ujfalusi 	ucontrol->value.enumerated.item[0] = rx51_spk_func;
122f2055e14SPeter Ujfalusi 
123f2055e14SPeter Ujfalusi 	return 0;
124f2055e14SPeter Ujfalusi }
125f2055e14SPeter Ujfalusi 
126f2055e14SPeter Ujfalusi static int rx51_set_spk(struct snd_kcontrol *kcontrol,
127f2055e14SPeter Ujfalusi 			struct snd_ctl_elem_value *ucontrol)
128f2055e14SPeter Ujfalusi {
129f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
130f2055e14SPeter Ujfalusi 
131f2055e14SPeter Ujfalusi 	if (rx51_spk_func == ucontrol->value.enumerated.item[0])
132f2055e14SPeter Ujfalusi 		return 0;
133f2055e14SPeter Ujfalusi 
134f2055e14SPeter Ujfalusi 	rx51_spk_func = ucontrol->value.enumerated.item[0];
135f2055e14SPeter Ujfalusi 	rx51_ext_control(&card->dapm);
136f2055e14SPeter Ujfalusi 
137f2055e14SPeter Ujfalusi 	return 1;
138f2055e14SPeter Ujfalusi }
139f2055e14SPeter Ujfalusi 
140f2055e14SPeter Ujfalusi static int rx51_spk_event(struct snd_soc_dapm_widget *w,
141f2055e14SPeter Ujfalusi 			  struct snd_kcontrol *k, int event)
142f2055e14SPeter Ujfalusi {
143f2055e14SPeter Ujfalusi 	struct snd_soc_dapm_context *dapm = w->dapm;
144f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = dapm->card;
145f2055e14SPeter Ujfalusi 	struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
146f2055e14SPeter Ujfalusi 
147f2055e14SPeter Ujfalusi 	gpiod_set_raw_value_cansleep(pdata->speaker_amp_gpio,
148f2055e14SPeter Ujfalusi 				     !!SND_SOC_DAPM_EVENT_ON(event));
149f2055e14SPeter Ujfalusi 
150f2055e14SPeter Ujfalusi 	return 0;
151f2055e14SPeter Ujfalusi }
152f2055e14SPeter Ujfalusi 
153f2055e14SPeter Ujfalusi static int rx51_get_input(struct snd_kcontrol *kcontrol,
154f2055e14SPeter Ujfalusi 			  struct snd_ctl_elem_value *ucontrol)
155f2055e14SPeter Ujfalusi {
156f2055e14SPeter Ujfalusi 	ucontrol->value.enumerated.item[0] = rx51_dmic_func;
157f2055e14SPeter Ujfalusi 
158f2055e14SPeter Ujfalusi 	return 0;
159f2055e14SPeter Ujfalusi }
160f2055e14SPeter Ujfalusi 
161f2055e14SPeter Ujfalusi static int rx51_set_input(struct snd_kcontrol *kcontrol,
162f2055e14SPeter Ujfalusi 			  struct snd_ctl_elem_value *ucontrol)
163f2055e14SPeter Ujfalusi {
164f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
165f2055e14SPeter Ujfalusi 
166f2055e14SPeter Ujfalusi 	if (rx51_dmic_func == ucontrol->value.enumerated.item[0])
167f2055e14SPeter Ujfalusi 		return 0;
168f2055e14SPeter Ujfalusi 
169f2055e14SPeter Ujfalusi 	rx51_dmic_func = ucontrol->value.enumerated.item[0];
170f2055e14SPeter Ujfalusi 	rx51_ext_control(&card->dapm);
171f2055e14SPeter Ujfalusi 
172f2055e14SPeter Ujfalusi 	return 1;
173f2055e14SPeter Ujfalusi }
174f2055e14SPeter Ujfalusi 
175f2055e14SPeter Ujfalusi static int rx51_get_jack(struct snd_kcontrol *kcontrol,
176f2055e14SPeter Ujfalusi 			 struct snd_ctl_elem_value *ucontrol)
177f2055e14SPeter Ujfalusi {
178f2055e14SPeter Ujfalusi 	ucontrol->value.enumerated.item[0] = rx51_jack_func;
179f2055e14SPeter Ujfalusi 
180f2055e14SPeter Ujfalusi 	return 0;
181f2055e14SPeter Ujfalusi }
182f2055e14SPeter Ujfalusi 
183f2055e14SPeter Ujfalusi static int rx51_set_jack(struct snd_kcontrol *kcontrol,
184f2055e14SPeter Ujfalusi 			 struct snd_ctl_elem_value *ucontrol)
185f2055e14SPeter Ujfalusi {
186f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
187f2055e14SPeter Ujfalusi 
188f2055e14SPeter Ujfalusi 	if (rx51_jack_func == ucontrol->value.enumerated.item[0])
189f2055e14SPeter Ujfalusi 		return 0;
190f2055e14SPeter Ujfalusi 
191f2055e14SPeter Ujfalusi 	rx51_jack_func = ucontrol->value.enumerated.item[0];
192f2055e14SPeter Ujfalusi 	rx51_ext_control(&card->dapm);
193f2055e14SPeter Ujfalusi 
194f2055e14SPeter Ujfalusi 	return 1;
195f2055e14SPeter Ujfalusi }
196f2055e14SPeter Ujfalusi 
197f2055e14SPeter Ujfalusi static struct snd_soc_jack rx51_av_jack;
198f2055e14SPeter Ujfalusi 
199f2055e14SPeter Ujfalusi static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
200f2055e14SPeter Ujfalusi 	{
201f2055e14SPeter Ujfalusi 		.name = "avdet-gpio",
202f2055e14SPeter Ujfalusi 		.report = SND_JACK_HEADSET,
203f2055e14SPeter Ujfalusi 		.invert = 1,
204f2055e14SPeter Ujfalusi 		.debounce_time = 200,
205f2055e14SPeter Ujfalusi 	},
206f2055e14SPeter Ujfalusi };
207f2055e14SPeter Ujfalusi 
208f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
209f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
210f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_MIC("DMic", NULL),
211f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
212f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_MIC("HS Mic", NULL),
213f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_LINE("FM Transmitter", NULL),
214f2055e14SPeter Ujfalusi 	SND_SOC_DAPM_SPK("Earphone", NULL),
215f2055e14SPeter Ujfalusi };
216f2055e14SPeter Ujfalusi 
217f2055e14SPeter Ujfalusi static const struct snd_soc_dapm_route audio_map[] = {
218f2055e14SPeter Ujfalusi 	{"Ext Spk", NULL, "HPLOUT"},
219f2055e14SPeter Ujfalusi 	{"Ext Spk", NULL, "HPROUT"},
220f2055e14SPeter Ujfalusi 	{"Ext Spk", NULL, "HPLCOM"},
221f2055e14SPeter Ujfalusi 	{"Ext Spk", NULL, "HPRCOM"},
222f2055e14SPeter Ujfalusi 	{"FM Transmitter", NULL, "LLOUT"},
223f2055e14SPeter Ujfalusi 	{"FM Transmitter", NULL, "RLOUT"},
224f2055e14SPeter Ujfalusi 
225f2055e14SPeter Ujfalusi 	{"Headphone Jack", NULL, "TPA6130A2 HPLEFT"},
226f2055e14SPeter Ujfalusi 	{"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"},
227f2055e14SPeter Ujfalusi 	{"TPA6130A2 LEFTIN", NULL, "LLOUT"},
228f2055e14SPeter Ujfalusi 	{"TPA6130A2 RIGHTIN", NULL, "RLOUT"},
229f2055e14SPeter Ujfalusi 
230f2055e14SPeter Ujfalusi 	{"DMic Rate 64", NULL, "DMic"},
231f2055e14SPeter Ujfalusi 	{"DMic", NULL, "Mic Bias"},
232f2055e14SPeter Ujfalusi 
233f2055e14SPeter Ujfalusi 	{"b LINE2R", NULL, "MONO_LOUT"},
234f2055e14SPeter Ujfalusi 	{"Earphone", NULL, "b HPLOUT"},
235f2055e14SPeter Ujfalusi 
236f2055e14SPeter Ujfalusi 	{"LINE1L", NULL, "HS Mic"},
237f2055e14SPeter Ujfalusi 	{"HS Mic", NULL, "b Mic Bias"},
238f2055e14SPeter Ujfalusi };
239f2055e14SPeter Ujfalusi 
240f2055e14SPeter Ujfalusi static const char * const spk_function[] = {"Off", "On"};
241f2055e14SPeter Ujfalusi static const char * const input_function[] = {"ADC", "Digital Mic"};
242f2055e14SPeter Ujfalusi static const char * const jack_function[] = {
243f2055e14SPeter Ujfalusi 	"Off", "TV-OUT", "Headphone", "Headset"
244f2055e14SPeter Ujfalusi };
245f2055e14SPeter Ujfalusi 
246f2055e14SPeter Ujfalusi static const struct soc_enum rx51_enum[] = {
247f2055e14SPeter Ujfalusi 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
248f2055e14SPeter Ujfalusi 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
249f2055e14SPeter Ujfalusi 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
250f2055e14SPeter Ujfalusi };
251f2055e14SPeter Ujfalusi 
252f2055e14SPeter Ujfalusi static const struct snd_kcontrol_new aic34_rx51_controls[] = {
253f2055e14SPeter Ujfalusi 	SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
254f2055e14SPeter Ujfalusi 		     rx51_get_spk, rx51_set_spk),
255f2055e14SPeter Ujfalusi 	SOC_ENUM_EXT("Input Select",  rx51_enum[1],
256f2055e14SPeter Ujfalusi 		     rx51_get_input, rx51_set_input),
257f2055e14SPeter Ujfalusi 	SOC_ENUM_EXT("Jack Function", rx51_enum[2],
258f2055e14SPeter Ujfalusi 		     rx51_get_jack, rx51_set_jack),
259f2055e14SPeter Ujfalusi 	SOC_DAPM_PIN_SWITCH("FM Transmitter"),
260f2055e14SPeter Ujfalusi 	SOC_DAPM_PIN_SWITCH("Earphone"),
261f2055e14SPeter Ujfalusi };
262f2055e14SPeter Ujfalusi 
263f2055e14SPeter Ujfalusi static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
264f2055e14SPeter Ujfalusi {
265f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = rtd->card;
266f2055e14SPeter Ujfalusi 	struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card);
267f2055e14SPeter Ujfalusi 	int err;
268f2055e14SPeter Ujfalusi 
269f2055e14SPeter Ujfalusi 	snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42);
270f2055e14SPeter Ujfalusi 
271f2055e14SPeter Ujfalusi 	err = omap_mcbsp_st_add_controls(rtd, 2);
272f2055e14SPeter Ujfalusi 	if (err < 0) {
273f2055e14SPeter Ujfalusi 		dev_err(card->dev, "Failed to add MCBSP controls\n");
274f2055e14SPeter Ujfalusi 		return err;
275f2055e14SPeter Ujfalusi 	}
276f2055e14SPeter Ujfalusi 
277f2055e14SPeter Ujfalusi 	/* AV jack detection */
278f2055e14SPeter Ujfalusi 	err = snd_soc_card_jack_new(rtd->card, "AV Jack",
279f2055e14SPeter Ujfalusi 				    SND_JACK_HEADSET | SND_JACK_VIDEOOUT,
280f2055e14SPeter Ujfalusi 				    &rx51_av_jack, NULL, 0);
281f2055e14SPeter Ujfalusi 	if (err) {
282f2055e14SPeter Ujfalusi 		dev_err(card->dev, "Failed to add AV Jack\n");
283f2055e14SPeter Ujfalusi 		return err;
284f2055e14SPeter Ujfalusi 	}
285f2055e14SPeter Ujfalusi 
286f2055e14SPeter Ujfalusi 	/* prepare gpio for snd_soc_jack_add_gpios */
287f2055e14SPeter Ujfalusi 	rx51_av_jack_gpios[0].gpio = desc_to_gpio(pdata->jack_detection_gpio);
288f2055e14SPeter Ujfalusi 	devm_gpiod_put(card->dev, pdata->jack_detection_gpio);
289f2055e14SPeter Ujfalusi 
290f2055e14SPeter Ujfalusi 	err = snd_soc_jack_add_gpios(&rx51_av_jack,
291f2055e14SPeter Ujfalusi 				     ARRAY_SIZE(rx51_av_jack_gpios),
292f2055e14SPeter Ujfalusi 				     rx51_av_jack_gpios);
293f2055e14SPeter Ujfalusi 	if (err) {
294f2055e14SPeter Ujfalusi 		dev_err(card->dev, "Failed to add GPIOs\n");
295f2055e14SPeter Ujfalusi 		return err;
296f2055e14SPeter Ujfalusi 	}
297f2055e14SPeter Ujfalusi 
298f2055e14SPeter Ujfalusi 	return err;
299f2055e14SPeter Ujfalusi }
300f2055e14SPeter Ujfalusi 
301f2055e14SPeter Ujfalusi /* Digital audio interface glue - connects codec <--> CPU */
302c3e2a4afSKuninori Morimoto SND_SOC_DAILINK_DEFS(aic34,
303c3e2a4afSKuninori Morimoto 	DAILINK_COMP_ARRAY(COMP_CPU("omap-mcbsp.2")),
304c3e2a4afSKuninori Morimoto 	DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.2-0018",
305569440b4SKuninori Morimoto 				      "tlv320aic3x-hifi")),
306569440b4SKuninori Morimoto 	DAILINK_COMP_ARRAY(COMP_PLATFORM("omap-mcbsp.2")));
307c3e2a4afSKuninori Morimoto 
308f2055e14SPeter Ujfalusi static struct snd_soc_dai_link rx51_dai[] = {
309f2055e14SPeter Ujfalusi 	{
310f2055e14SPeter Ujfalusi 		.name = "TLV320AIC34",
311f2055e14SPeter Ujfalusi 		.stream_name = "AIC34",
312f2055e14SPeter Ujfalusi 		.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
313f2055e14SPeter Ujfalusi 			   SND_SOC_DAIFMT_CBM_CFM,
314f2055e14SPeter Ujfalusi 		.init = rx51_aic34_init,
315f2055e14SPeter Ujfalusi 		.ops = &rx51_ops,
316c3e2a4afSKuninori Morimoto 		SND_SOC_DAILINK_REG(aic34),
317f2055e14SPeter Ujfalusi 	},
318f2055e14SPeter Ujfalusi };
319f2055e14SPeter Ujfalusi 
320f2055e14SPeter Ujfalusi static struct snd_soc_aux_dev rx51_aux_dev[] = {
321f2055e14SPeter Ujfalusi 	{
32277b21d28SKuninori Morimoto 		.dlc = COMP_AUX("tlv320aic3x-codec.2-0019"),
323f2055e14SPeter Ujfalusi 	},
324f2055e14SPeter Ujfalusi 	{
32577b21d28SKuninori Morimoto 		.dlc = COMP_AUX("tpa6130a2.2-0060"),
326f2055e14SPeter Ujfalusi 	},
327f2055e14SPeter Ujfalusi };
328f2055e14SPeter Ujfalusi 
329f2055e14SPeter Ujfalusi static struct snd_soc_codec_conf rx51_codec_conf[] = {
330f2055e14SPeter Ujfalusi 	{
331e3c157c9SKuninori Morimoto 		.dlc = COMP_CODEC_CONF("tlv320aic3x-codec.2-0019"),
332f2055e14SPeter Ujfalusi 		.name_prefix = "b",
333f2055e14SPeter Ujfalusi 	},
334f2055e14SPeter Ujfalusi 	{
335e3c157c9SKuninori Morimoto 		.dlc = COMP_CODEC_CONF("tpa6130a2.2-0060"),
336f2055e14SPeter Ujfalusi 		.name_prefix = "TPA6130A2",
337f2055e14SPeter Ujfalusi 	},
338f2055e14SPeter Ujfalusi };
339f2055e14SPeter Ujfalusi 
340f2055e14SPeter Ujfalusi /* Audio card */
341f2055e14SPeter Ujfalusi static struct snd_soc_card rx51_sound_card = {
342f2055e14SPeter Ujfalusi 	.name = "RX-51",
343f2055e14SPeter Ujfalusi 	.owner = THIS_MODULE,
344f2055e14SPeter Ujfalusi 	.dai_link = rx51_dai,
345f2055e14SPeter Ujfalusi 	.num_links = ARRAY_SIZE(rx51_dai),
346f2055e14SPeter Ujfalusi 	.aux_dev = rx51_aux_dev,
347f2055e14SPeter Ujfalusi 	.num_aux_devs = ARRAY_SIZE(rx51_aux_dev),
348f2055e14SPeter Ujfalusi 	.codec_conf = rx51_codec_conf,
349f2055e14SPeter Ujfalusi 	.num_configs = ARRAY_SIZE(rx51_codec_conf),
350f2055e14SPeter Ujfalusi 	.fully_routed = true,
351f2055e14SPeter Ujfalusi 
352f2055e14SPeter Ujfalusi 	.controls = aic34_rx51_controls,
353f2055e14SPeter Ujfalusi 	.num_controls = ARRAY_SIZE(aic34_rx51_controls),
354f2055e14SPeter Ujfalusi 	.dapm_widgets = aic34_dapm_widgets,
355f2055e14SPeter Ujfalusi 	.num_dapm_widgets = ARRAY_SIZE(aic34_dapm_widgets),
356f2055e14SPeter Ujfalusi 	.dapm_routes = audio_map,
357f2055e14SPeter Ujfalusi 	.num_dapm_routes = ARRAY_SIZE(audio_map),
358f2055e14SPeter Ujfalusi };
359f2055e14SPeter Ujfalusi 
360f2055e14SPeter Ujfalusi static int rx51_soc_probe(struct platform_device *pdev)
361f2055e14SPeter Ujfalusi {
362f2055e14SPeter Ujfalusi 	struct rx51_audio_pdata *pdata;
363f2055e14SPeter Ujfalusi 	struct device_node *np = pdev->dev.of_node;
364f2055e14SPeter Ujfalusi 	struct snd_soc_card *card = &rx51_sound_card;
365f2055e14SPeter Ujfalusi 	int err;
366f2055e14SPeter Ujfalusi 
367f2055e14SPeter Ujfalusi 	if (!machine_is_nokia_rx51() && !of_machine_is_compatible("nokia,omap3-n900"))
368f2055e14SPeter Ujfalusi 		return -ENODEV;
369f2055e14SPeter Ujfalusi 
370f2055e14SPeter Ujfalusi 	card->dev = &pdev->dev;
371f2055e14SPeter Ujfalusi 
372f2055e14SPeter Ujfalusi 	if (np) {
373f2055e14SPeter Ujfalusi 		struct device_node *dai_node;
374f2055e14SPeter Ujfalusi 
375f2055e14SPeter Ujfalusi 		dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
376f2055e14SPeter Ujfalusi 		if (!dai_node) {
377f2055e14SPeter Ujfalusi 			dev_err(&pdev->dev, "McBSP node is not provided\n");
378f2055e14SPeter Ujfalusi 			return -EINVAL;
379f2055e14SPeter Ujfalusi 		}
380c3e2a4afSKuninori Morimoto 		rx51_dai[0].cpus->dai_name = NULL;
381569440b4SKuninori Morimoto 		rx51_dai[0].platforms->name = NULL;
382c3e2a4afSKuninori Morimoto 		rx51_dai[0].cpus->of_node = dai_node;
383569440b4SKuninori Morimoto 		rx51_dai[0].platforms->of_node = dai_node;
384f2055e14SPeter Ujfalusi 
385f2055e14SPeter Ujfalusi 		dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
386f2055e14SPeter Ujfalusi 		if (!dai_node) {
387f2055e14SPeter Ujfalusi 			dev_err(&pdev->dev, "Codec node is not provided\n");
388f2055e14SPeter Ujfalusi 			return -EINVAL;
389f2055e14SPeter Ujfalusi 		}
390c3e2a4afSKuninori Morimoto 		rx51_dai[0].codecs->name = NULL;
391c3e2a4afSKuninori Morimoto 		rx51_dai[0].codecs->of_node = dai_node;
392f2055e14SPeter Ujfalusi 
393f2055e14SPeter Ujfalusi 		dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
394f2055e14SPeter Ujfalusi 		if (!dai_node) {
395f2055e14SPeter Ujfalusi 			dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n");
396f2055e14SPeter Ujfalusi 			return -EINVAL;
397f2055e14SPeter Ujfalusi 		}
39877b21d28SKuninori Morimoto 		rx51_aux_dev[0].dlc.name = NULL;
39977b21d28SKuninori Morimoto 		rx51_aux_dev[0].dlc.of_node = dai_node;
400e3c157c9SKuninori Morimoto 		rx51_codec_conf[0].dlc.name = NULL;
401e3c157c9SKuninori Morimoto 		rx51_codec_conf[0].dlc.of_node = dai_node;
402f2055e14SPeter Ujfalusi 
403f2055e14SPeter Ujfalusi 		dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
404f2055e14SPeter Ujfalusi 		if (!dai_node) {
405f2055e14SPeter Ujfalusi 			dev_err(&pdev->dev, "Headphone amplifier node is not provided\n");
406f2055e14SPeter Ujfalusi 			return -EINVAL;
407f2055e14SPeter Ujfalusi 		}
40877b21d28SKuninori Morimoto 		rx51_aux_dev[1].dlc.name = NULL;
40977b21d28SKuninori Morimoto 		rx51_aux_dev[1].dlc.of_node = dai_node;
410e3c157c9SKuninori Morimoto 		rx51_codec_conf[1].dlc.name = NULL;
411e3c157c9SKuninori Morimoto 		rx51_codec_conf[1].dlc.of_node = dai_node;
412f2055e14SPeter Ujfalusi 	}
413f2055e14SPeter Ujfalusi 
414f2055e14SPeter Ujfalusi 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
415f2055e14SPeter Ujfalusi 	if (pdata == NULL)
416f2055e14SPeter Ujfalusi 		return -ENOMEM;
417f2055e14SPeter Ujfalusi 
418f2055e14SPeter Ujfalusi 	snd_soc_card_set_drvdata(card, pdata);
419f2055e14SPeter Ujfalusi 
420f2055e14SPeter Ujfalusi 	pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
421f2055e14SPeter Ujfalusi 						     "tvout-selection",
422f2055e14SPeter Ujfalusi 						     GPIOD_OUT_LOW);
423f2055e14SPeter Ujfalusi 	if (IS_ERR(pdata->tvout_selection_gpio)) {
424f2055e14SPeter Ujfalusi 		dev_err(card->dev, "could not get tvout selection gpio\n");
425f2055e14SPeter Ujfalusi 		return PTR_ERR(pdata->tvout_selection_gpio);
426f2055e14SPeter Ujfalusi 	}
427f2055e14SPeter Ujfalusi 
428f2055e14SPeter Ujfalusi 	pdata->jack_detection_gpio = devm_gpiod_get(card->dev,
429f2055e14SPeter Ujfalusi 						    "jack-detection",
430f2055e14SPeter Ujfalusi 						    GPIOD_ASIS);
431f2055e14SPeter Ujfalusi 	if (IS_ERR(pdata->jack_detection_gpio)) {
432f2055e14SPeter Ujfalusi 		dev_err(card->dev, "could not get jack detection gpio\n");
433f2055e14SPeter Ujfalusi 		return PTR_ERR(pdata->jack_detection_gpio);
434f2055e14SPeter Ujfalusi 	}
435f2055e14SPeter Ujfalusi 
436f2055e14SPeter Ujfalusi 	pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
437f2055e14SPeter Ujfalusi 					    GPIOD_OUT_HIGH);
438f2055e14SPeter Ujfalusi 	if (IS_ERR(pdata->eci_sw_gpio)) {
439f2055e14SPeter Ujfalusi 		dev_err(card->dev, "could not get eci switch gpio\n");
440f2055e14SPeter Ujfalusi 		return PTR_ERR(pdata->eci_sw_gpio);
441f2055e14SPeter Ujfalusi 	}
442f2055e14SPeter Ujfalusi 
443f2055e14SPeter Ujfalusi 	pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
444f2055e14SPeter Ujfalusi 						 "speaker-amplifier",
445f2055e14SPeter Ujfalusi 						 GPIOD_OUT_LOW);
446f2055e14SPeter Ujfalusi 	if (IS_ERR(pdata->speaker_amp_gpio)) {
447f2055e14SPeter Ujfalusi 		dev_err(card->dev, "could not get speaker enable gpio\n");
448f2055e14SPeter Ujfalusi 		return PTR_ERR(pdata->speaker_amp_gpio);
449f2055e14SPeter Ujfalusi 	}
450f2055e14SPeter Ujfalusi 
451f2055e14SPeter Ujfalusi 	err = devm_snd_soc_register_card(card->dev, card);
452f2055e14SPeter Ujfalusi 	if (err) {
453f2055e14SPeter Ujfalusi 		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err);
454f2055e14SPeter Ujfalusi 		return err;
455f2055e14SPeter Ujfalusi 	}
456f2055e14SPeter Ujfalusi 
457f2055e14SPeter Ujfalusi 	return 0;
458f2055e14SPeter Ujfalusi }
459f2055e14SPeter Ujfalusi 
460f2055e14SPeter Ujfalusi #if defined(CONFIG_OF)
461f2055e14SPeter Ujfalusi static const struct of_device_id rx51_audio_of_match[] = {
462f2055e14SPeter Ujfalusi 	{ .compatible = "nokia,n900-audio", },
463f2055e14SPeter Ujfalusi 	{},
464f2055e14SPeter Ujfalusi };
465f2055e14SPeter Ujfalusi MODULE_DEVICE_TABLE(of, rx51_audio_of_match);
466f2055e14SPeter Ujfalusi #endif
467f2055e14SPeter Ujfalusi 
468f2055e14SPeter Ujfalusi static struct platform_driver rx51_soc_driver = {
469f2055e14SPeter Ujfalusi 	.driver = {
470f2055e14SPeter Ujfalusi 		.name = "rx51-audio",
471f2055e14SPeter Ujfalusi 		.of_match_table = of_match_ptr(rx51_audio_of_match),
472f2055e14SPeter Ujfalusi 	},
473f2055e14SPeter Ujfalusi 	.probe = rx51_soc_probe,
474f2055e14SPeter Ujfalusi };
475f2055e14SPeter Ujfalusi 
476f2055e14SPeter Ujfalusi module_platform_driver(rx51_soc_driver);
477f2055e14SPeter Ujfalusi 
478f2055e14SPeter Ujfalusi MODULE_AUTHOR("Nokia Corporation");
479f2055e14SPeter Ujfalusi MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
480f2055e14SPeter Ujfalusi MODULE_LICENSE("GPL");
481f2055e14SPeter Ujfalusi MODULE_ALIAS("platform:rx51-audio");
482