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