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 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 88f2055e14SPeter Ujfalusi static int rx51_startup(struct snd_pcm_substream *substream) 89f2055e14SPeter Ujfalusi { 90f2055e14SPeter Ujfalusi struct snd_pcm_runtime *runtime = substream->runtime; 9102cde14aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_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 100f2055e14SPeter Ujfalusi static int rx51_hw_params(struct snd_pcm_substream *substream, 101f2055e14SPeter Ujfalusi struct snd_pcm_hw_params *params) 102f2055e14SPeter Ujfalusi { 10302cde14aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1042842b871SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_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 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 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 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 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 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 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 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 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 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