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