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; 5822581e7cSGustavo A. R. Silva /* fall through */ 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; 93f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 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 { 105f2055e14SPeter Ujfalusi struct snd_soc_pcm_runtime *rtd = substream->private_data; 106f2055e14SPeter Ujfalusi struct snd_soc_dai *codec_dai = rtd->codec_dai; 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 { 331*e3c157c9SKuninori Morimoto .dlc = COMP_CODEC_CONF("tlv320aic3x-codec.2-0019"), 332f2055e14SPeter Ujfalusi .name_prefix = "b", 333f2055e14SPeter Ujfalusi }, 334f2055e14SPeter Ujfalusi { 335*e3c157c9SKuninori 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; 400*e3c157c9SKuninori Morimoto rx51_codec_conf[0].dlc.name = NULL; 401*e3c157c9SKuninori 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; 410*e3c157c9SKuninori Morimoto rx51_codec_conf[1].dlc.name = NULL; 411*e3c157c9SKuninori 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