| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 1 | /* | 
 | 2 |  * rx51.c  --  SoC audio for Nokia RX-51 | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2008 - 2009 Nokia Corporation | 
 | 5 |  * | 
 | 6 |  * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com> | 
 | 7 |  *          Eduardo Valentin <eduardo.valentin@nokia.com> | 
 | 8 |  *          Jarkko Nikula <jhnikula@gmail.com> | 
 | 9 |  * | 
 | 10 |  * This program is free software; you can redistribute it and/or | 
 | 11 |  * modify it under the terms of the GNU General Public License | 
 | 12 |  * version 2 as published by the Free Software Foundation. | 
 | 13 |  * | 
 | 14 |  * This program is distributed in the hope that it will be useful, but | 
 | 15 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 16 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | 17 |  * General Public License for more details. | 
 | 18 |  * | 
 | 19 |  * You should have received a copy of the GNU General Public License | 
 | 20 |  * along with this program; if not, write to the Free Software | 
 | 21 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
 | 22 |  * 02110-1301 USA | 
 | 23 |  * | 
 | 24 |  */ | 
 | 25 |  | 
 | 26 | #include <linux/delay.h> | 
 | 27 | #include <linux/gpio.h> | 
 | 28 | #include <linux/platform_device.h> | 
 | 29 | #include <sound/core.h> | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 30 | #include <sound/jack.h> | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 31 | #include <sound/pcm.h> | 
 | 32 | #include <sound/soc.h> | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 33 | #include <plat/mcbsp.h> | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 34 | #include "../codecs/tpa6130a2.h" | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 35 |  | 
 | 36 | #include <asm/mach-types.h> | 
 | 37 |  | 
 | 38 | #include "omap-mcbsp.h" | 
 | 39 | #include "omap-pcm.h" | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 40 |  | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 41 | #define RX51_TVOUT_SEL_GPIO		40 | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 42 | #define RX51_JACK_DETECT_GPIO		177 | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 43 | #define RX51_ECI_SW_GPIO		182 | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 44 | /* | 
 | 45 |  * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This | 
 | 46 |  * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c | 
 | 47 |  */ | 
 | 48 | #define RX51_SPEAKER_AMP_TWL_GPIO	(192 + 7) | 
 | 49 |  | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 50 | enum { | 
 | 51 | 	RX51_JACK_DISABLED, | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 52 | 	RX51_JACK_TVOUT,		/* tv-out with stereo output */ | 
 | 53 | 	RX51_JACK_HP,			/* headphone: stereo output, no mic */ | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 54 | 	RX51_JACK_HS,			/* headset: stereo output with mic */ | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 55 | }; | 
 | 56 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 57 | static int rx51_spk_func; | 
 | 58 | static int rx51_dmic_func; | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 59 | static int rx51_jack_func; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 60 |  | 
 | 61 | static void rx51_ext_control(struct snd_soc_codec *codec) | 
 | 62 | { | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 63 | 	struct snd_soc_dapm_context *dapm = &codec->dapm; | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 64 | 	int hp = 0, hs = 0, tvout = 0; | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 65 |  | 
 | 66 | 	switch (rx51_jack_func) { | 
 | 67 | 	case RX51_JACK_TVOUT: | 
 | 68 | 		tvout = 1; | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 69 | 		hp = 1; | 
 | 70 | 		break; | 
 | 71 | 	case RX51_JACK_HS: | 
 | 72 | 		hs = 1; | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 73 | 	case RX51_JACK_HP: | 
 | 74 | 		hp = 1; | 
 | 75 | 		break; | 
 | 76 | 	} | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 77 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 78 | 	if (rx51_spk_func) | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 79 | 		snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 80 | 	else | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 81 | 		snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 82 | 	if (rx51_dmic_func) | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 83 | 		snd_soc_dapm_enable_pin(dapm, "DMic"); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 84 | 	else | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 85 | 		snd_soc_dapm_disable_pin(dapm, "DMic"); | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 86 | 	if (hp) | 
 | 87 | 		snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 
 | 88 | 	else | 
 | 89 | 		snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 90 | 	if (hs) | 
 | 91 | 		snd_soc_dapm_enable_pin(dapm, "HS Mic"); | 
 | 92 | 	else | 
 | 93 | 		snd_soc_dapm_disable_pin(dapm, "HS Mic"); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 94 |  | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 95 | 	gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 96 |  | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 97 | 	snd_soc_dapm_sync(dapm); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 98 | } | 
 | 99 |  | 
 | 100 | static int rx51_startup(struct snd_pcm_substream *substream) | 
 | 101 | { | 
 | 102 | 	struct snd_pcm_runtime *runtime = substream->runtime; | 
 | 103 | 	struct snd_soc_pcm_runtime *rtd = substream->private_data; | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 104 | 	struct snd_soc_codec *codec = rtd->codec; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 105 |  | 
 | 106 | 	snd_pcm_hw_constraint_minmax(runtime, | 
 | 107 | 				     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); | 
 | 108 | 	rx51_ext_control(codec); | 
 | 109 |  | 
 | 110 | 	return 0; | 
 | 111 | } | 
 | 112 |  | 
 | 113 | static int rx51_hw_params(struct snd_pcm_substream *substream, | 
 | 114 | 	struct snd_pcm_hw_params *params) | 
 | 115 | { | 
 | 116 | 	struct snd_soc_pcm_runtime *rtd = substream->private_data; | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 117 | 	struct snd_soc_dai *codec_dai = rtd->codec_dai; | 
 | 118 | 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 119 | 	int err; | 
 | 120 |  | 
 | 121 | 	/* Set codec DAI configuration */ | 
 | 122 | 	err = snd_soc_dai_set_fmt(codec_dai, | 
 | 123 | 				  SND_SOC_DAIFMT_DSP_A | | 
 | 124 | 				  SND_SOC_DAIFMT_IB_NF | | 
 | 125 | 				  SND_SOC_DAIFMT_CBM_CFM); | 
 | 126 | 	if (err < 0) | 
 | 127 | 		return err; | 
 | 128 |  | 
 | 129 | 	/* Set cpu DAI configuration */ | 
 | 130 | 	err = snd_soc_dai_set_fmt(cpu_dai, | 
 | 131 | 				  SND_SOC_DAIFMT_DSP_A | | 
 | 132 | 				  SND_SOC_DAIFMT_IB_NF | | 
 | 133 | 				  SND_SOC_DAIFMT_CBM_CFM); | 
 | 134 | 	if (err < 0) | 
 | 135 | 		return err; | 
 | 136 |  | 
 | 137 | 	/* Set the codec system clock for DAC and ADC */ | 
 | 138 | 	return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000, | 
 | 139 | 				      SND_SOC_CLOCK_IN); | 
 | 140 | } | 
 | 141 |  | 
 | 142 | static struct snd_soc_ops rx51_ops = { | 
 | 143 | 	.startup = rx51_startup, | 
 | 144 | 	.hw_params = rx51_hw_params, | 
 | 145 | }; | 
 | 146 |  | 
 | 147 | static int rx51_get_spk(struct snd_kcontrol *kcontrol, | 
 | 148 | 			struct snd_ctl_elem_value *ucontrol) | 
 | 149 | { | 
 | 150 | 	ucontrol->value.integer.value[0] = rx51_spk_func; | 
 | 151 |  | 
 | 152 | 	return 0; | 
 | 153 | } | 
 | 154 |  | 
 | 155 | static int rx51_set_spk(struct snd_kcontrol *kcontrol, | 
 | 156 | 			struct snd_ctl_elem_value *ucontrol) | 
 | 157 | { | 
 | 158 | 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 
 | 159 |  | 
 | 160 | 	if (rx51_spk_func == ucontrol->value.integer.value[0]) | 
 | 161 | 		return 0; | 
 | 162 |  | 
 | 163 | 	rx51_spk_func = ucontrol->value.integer.value[0]; | 
 | 164 | 	rx51_ext_control(codec); | 
 | 165 |  | 
 | 166 | 	return 1; | 
 | 167 | } | 
 | 168 |  | 
 | 169 | static int rx51_spk_event(struct snd_soc_dapm_widget *w, | 
 | 170 | 			  struct snd_kcontrol *k, int event) | 
 | 171 | { | 
 | 172 | 	if (SND_SOC_DAPM_EVENT_ON(event)) | 
| Jarkko Nikula | 4fff7a5 | 2010-08-23 10:36:41 +0300 | [diff] [blame] | 173 | 		gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 174 | 	else | 
| Jarkko Nikula | 4fff7a5 | 2010-08-23 10:36:41 +0300 | [diff] [blame] | 175 | 		gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 176 |  | 
 | 177 | 	return 0; | 
 | 178 | } | 
 | 179 |  | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 180 | static int rx51_hp_event(struct snd_soc_dapm_widget *w, | 
 | 181 | 			 struct snd_kcontrol *k, int event) | 
 | 182 | { | 
 | 183 | 	struct snd_soc_codec *codec = w->dapm->codec; | 
 | 184 |  | 
 | 185 | 	if (SND_SOC_DAPM_EVENT_ON(event)) | 
 | 186 | 		tpa6130a2_stereo_enable(codec, 1); | 
 | 187 | 	else | 
 | 188 | 		tpa6130a2_stereo_enable(codec, 0); | 
 | 189 |  | 
 | 190 | 	return 0; | 
 | 191 | } | 
 | 192 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 193 | static int rx51_get_input(struct snd_kcontrol *kcontrol, | 
 | 194 | 			  struct snd_ctl_elem_value *ucontrol) | 
 | 195 | { | 
 | 196 | 	ucontrol->value.integer.value[0] = rx51_dmic_func; | 
 | 197 |  | 
 | 198 | 	return 0; | 
 | 199 | } | 
 | 200 |  | 
 | 201 | static int rx51_set_input(struct snd_kcontrol *kcontrol, | 
 | 202 | 			  struct snd_ctl_elem_value *ucontrol) | 
 | 203 | { | 
 | 204 | 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 
 | 205 |  | 
 | 206 | 	if (rx51_dmic_func == ucontrol->value.integer.value[0]) | 
 | 207 | 		return 0; | 
 | 208 |  | 
 | 209 | 	rx51_dmic_func = ucontrol->value.integer.value[0]; | 
 | 210 | 	rx51_ext_control(codec); | 
 | 211 |  | 
 | 212 | 	return 1; | 
 | 213 | } | 
 | 214 |  | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 215 | static int rx51_get_jack(struct snd_kcontrol *kcontrol, | 
 | 216 | 			 struct snd_ctl_elem_value *ucontrol) | 
 | 217 | { | 
 | 218 | 	ucontrol->value.integer.value[0] = rx51_jack_func; | 
 | 219 |  | 
 | 220 | 	return 0; | 
 | 221 | } | 
 | 222 |  | 
 | 223 | static int rx51_set_jack(struct snd_kcontrol *kcontrol, | 
 | 224 | 			 struct snd_ctl_elem_value *ucontrol) | 
 | 225 | { | 
 | 226 | 	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 
 | 227 |  | 
 | 228 | 	if (rx51_jack_func == ucontrol->value.integer.value[0]) | 
 | 229 | 		return 0; | 
 | 230 |  | 
 | 231 | 	rx51_jack_func = ucontrol->value.integer.value[0]; | 
 | 232 | 	rx51_ext_control(codec); | 
 | 233 |  | 
 | 234 | 	return 1; | 
 | 235 | } | 
 | 236 |  | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 237 | static struct snd_soc_jack rx51_av_jack; | 
 | 238 |  | 
 | 239 | static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { | 
 | 240 | 	{ | 
 | 241 | 		.gpio = RX51_JACK_DETECT_GPIO, | 
 | 242 | 		.name = "avdet-gpio", | 
| Jarkko Nikula | 1784061 | 2011-02-14 17:20:22 +0200 | [diff] [blame] | 243 | 		.report = SND_JACK_HEADSET, | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 244 | 		.invert = 1, | 
 | 245 | 		.debounce_time = 200, | 
 | 246 | 	}, | 
 | 247 | }; | 
 | 248 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 249 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | 
 | 250 | 	SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | 
 | 251 | 	SND_SOC_DAPM_MIC("DMic", NULL), | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 252 | 	SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 253 | 	SND_SOC_DAPM_MIC("HS Mic", NULL), | 
| Jarkko Nikula | 9d7e584 | 2011-02-21 14:57:22 +0200 | [diff] [blame] | 254 | 	SND_SOC_DAPM_LINE("FM Transmitter", NULL), | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 255 | }; | 
 | 256 |  | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 257 | static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = { | 
 | 258 | 	SND_SOC_DAPM_SPK("Earphone", NULL), | 
 | 259 | }; | 
 | 260 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 261 | static const struct snd_soc_dapm_route audio_map[] = { | 
 | 262 | 	{"Ext Spk", NULL, "HPLOUT"}, | 
 | 263 | 	{"Ext Spk", NULL, "HPROUT"}, | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 264 | 	{"Headphone Jack", NULL, "LLOUT"}, | 
 | 265 | 	{"Headphone Jack", NULL, "RLOUT"}, | 
| Jarkko Nikula | 9d7e584 | 2011-02-21 14:57:22 +0200 | [diff] [blame] | 266 | 	{"FM Transmitter", NULL, "LLOUT"}, | 
 | 267 | 	{"FM Transmitter", NULL, "RLOUT"}, | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 268 |  | 
 | 269 | 	{"DMic Rate 64", NULL, "Mic Bias 2V"}, | 
 | 270 | 	{"Mic Bias 2V", NULL, "DMic"}, | 
 | 271 | }; | 
 | 272 |  | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 273 | static const struct snd_soc_dapm_route audio_mapb[] = { | 
 | 274 | 	{"b LINE2R", NULL, "MONO_LOUT"}, | 
 | 275 | 	{"Earphone", NULL, "b HPLOUT"}, | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 276 |  | 
 | 277 | 	{"LINE1L", NULL, "b Mic Bias 2.5V"}, | 
 | 278 | 	{"b Mic Bias 2.5V", NULL, "HS Mic"} | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 279 | }; | 
 | 280 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 281 | static const char *spk_function[] = {"Off", "On"}; | 
 | 282 | static const char *input_function[] = {"ADC", "Digital Mic"}; | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 283 | static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"}; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 284 |  | 
 | 285 | static const struct soc_enum rx51_enum[] = { | 
 | 286 | 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 
 | 287 | 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 288 | 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 289 | }; | 
 | 290 |  | 
 | 291 | static const struct snd_kcontrol_new aic34_rx51_controls[] = { | 
 | 292 | 	SOC_ENUM_EXT("Speaker Function", rx51_enum[0], | 
 | 293 | 		     rx51_get_spk, rx51_set_spk), | 
 | 294 | 	SOC_ENUM_EXT("Input Select",  rx51_enum[1], | 
 | 295 | 		     rx51_get_input, rx51_set_input), | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 296 | 	SOC_ENUM_EXT("Jack Function", rx51_enum[2], | 
 | 297 | 		     rx51_get_jack, rx51_set_jack), | 
| Jarkko Nikula | 9d7e584 | 2011-02-21 14:57:22 +0200 | [diff] [blame] | 298 | 	SOC_DAPM_PIN_SWITCH("FM Transmitter"), | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 299 | }; | 
 | 300 |  | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 301 | static const struct snd_kcontrol_new aic34_rx51_controlsb[] = { | 
 | 302 | 	SOC_DAPM_PIN_SWITCH("Earphone"), | 
 | 303 | }; | 
 | 304 |  | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 305 | static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 306 | { | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 307 | 	struct snd_soc_codec *codec = rtd->codec; | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 308 | 	struct snd_soc_dapm_context *dapm = &codec->dapm; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 309 | 	int err; | 
 | 310 |  | 
 | 311 | 	/* Set up NC codec pins */ | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 312 | 	snd_soc_dapm_nc_pin(dapm, "MIC3L"); | 
 | 313 | 	snd_soc_dapm_nc_pin(dapm, "MIC3R"); | 
 | 314 | 	snd_soc_dapm_nc_pin(dapm, "LINE1R"); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 315 |  | 
 | 316 | 	/* Add RX-51 specific controls */ | 
 | 317 | 	err = snd_soc_add_controls(codec, aic34_rx51_controls, | 
 | 318 | 				   ARRAY_SIZE(aic34_rx51_controls)); | 
 | 319 | 	if (err < 0) | 
 | 320 | 		return err; | 
 | 321 |  | 
 | 322 | 	/* Add RX-51 specific widgets */ | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 323 | 	snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets, | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 324 | 				  ARRAY_SIZE(aic34_dapm_widgets)); | 
 | 325 |  | 
 | 326 | 	/* Set up RX-51 specific audio path audio_map */ | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 327 | 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 328 |  | 
| Jarkko Nikula | 48529b3 | 2011-01-27 16:47:11 +0200 | [diff] [blame] | 329 | 	err = tpa6130a2_add_controls(codec); | 
 | 330 | 	if (err < 0) | 
 | 331 | 		return err; | 
 | 332 | 	snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); | 
 | 333 |  | 
| Jarkko Nikula | fa4d1f5 | 2011-03-09 11:25:00 +0200 | [diff] [blame] | 334 | 	err = omap_mcbsp_st_add_controls(codec, 1); | 
 | 335 | 	if (err < 0) | 
 | 336 | 		return err; | 
 | 337 |  | 
| Liam Girdwood | ce6120c | 2010-11-05 15:53:46 +0200 | [diff] [blame] | 338 | 	snd_soc_dapm_sync(dapm); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 339 |  | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 340 | 	/* AV jack detection */ | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 341 | 	err = snd_soc_jack_new(codec, "AV Jack", | 
| Jarkko Nikula | 1784061 | 2011-02-14 17:20:22 +0200 | [diff] [blame] | 342 | 			       SND_JACK_HEADSET | SND_JACK_VIDEOOUT, | 
 | 343 | 			       &rx51_av_jack); | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 344 | 	if (err) | 
 | 345 | 		return err; | 
 | 346 | 	err = snd_soc_jack_add_gpios(&rx51_av_jack, | 
 | 347 | 				     ARRAY_SIZE(rx51_av_jack_gpios), | 
 | 348 | 				     rx51_av_jack_gpios); | 
 | 349 |  | 
 | 350 | 	return err; | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 351 | } | 
 | 352 |  | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 353 | static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm) | 
 | 354 | { | 
 | 355 | 	int err; | 
 | 356 |  | 
 | 357 | 	err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb, | 
 | 358 | 				   ARRAY_SIZE(aic34_rx51_controlsb)); | 
 | 359 | 	if (err < 0) | 
 | 360 | 		return err; | 
 | 361 |  | 
 | 362 | 	err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb, | 
 | 363 | 					ARRAY_SIZE(aic34_dapm_widgetsb)); | 
 | 364 | 	if (err < 0) | 
 | 365 | 		return 0; | 
 | 366 |  | 
 | 367 | 	return snd_soc_dapm_add_routes(dapm, audio_mapb, | 
 | 368 | 				       ARRAY_SIZE(audio_mapb)); | 
 | 369 | } | 
 | 370 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 371 | /* Digital audio interface glue - connects codec <--> CPU */ | 
 | 372 | static struct snd_soc_dai_link rx51_dai[] = { | 
 | 373 | 	{ | 
 | 374 | 		.name = "TLV320AIC34", | 
 | 375 | 		.stream_name = "AIC34", | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 376 | 		.cpu_dai_name = "omap-mcbsp-dai.1", | 
 | 377 | 		.codec_dai_name = "tlv320aic3x-hifi", | 
 | 378 | 		.platform_name = "omap-pcm-audio", | 
 | 379 | 		.codec_name = "tlv320aic3x-codec.2-0018", | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 380 | 		.init = rx51_aic34_init, | 
 | 381 | 		.ops = &rx51_ops, | 
 | 382 | 	}, | 
 | 383 | }; | 
 | 384 |  | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 385 | struct snd_soc_aux_dev rx51_aux_dev[] = { | 
 | 386 | 	{ | 
 | 387 | 		.name = "TLV320AIC34b", | 
 | 388 | 		.codec_name = "tlv320aic3x-codec.2-0019", | 
 | 389 | 		.init = rx51_aic34b_init, | 
 | 390 | 	}, | 
 | 391 | }; | 
 | 392 |  | 
 | 393 | static struct snd_soc_codec_conf rx51_codec_conf[] = { | 
 | 394 | 	{ | 
 | 395 | 		.dev_name = "tlv320aic3x-codec.2-0019", | 
 | 396 | 		.name_prefix = "b", | 
 | 397 | 	}, | 
 | 398 | }; | 
 | 399 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 400 | /* Audio card */ | 
 | 401 | static struct snd_soc_card rx51_sound_card = { | 
 | 402 | 	.name = "RX-51", | 
 | 403 | 	.dai_link = rx51_dai, | 
 | 404 | 	.num_links = ARRAY_SIZE(rx51_dai), | 
| Jarkko Nikula | 8cda975 | 2011-01-31 14:43:48 +0200 | [diff] [blame] | 405 | 	.aux_dev = rx51_aux_dev, | 
 | 406 | 	.num_aux_devs = ARRAY_SIZE(rx51_aux_dev), | 
 | 407 | 	.codec_conf = rx51_codec_conf, | 
 | 408 | 	.num_configs = ARRAY_SIZE(rx51_codec_conf), | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 409 | }; | 
 | 410 |  | 
 | 411 | static struct platform_device *rx51_snd_device; | 
 | 412 |  | 
 | 413 | static int __init rx51_soc_init(void) | 
 | 414 | { | 
 | 415 | 	int err; | 
 | 416 |  | 
 | 417 | 	if (!machine_is_nokia_rx51()) | 
 | 418 | 		return -ENODEV; | 
 | 419 |  | 
| Jarkko Nikula | d8ec598 | 2011-02-14 17:20:20 +0200 | [diff] [blame] | 420 | 	err = gpio_request_one(RX51_TVOUT_SEL_GPIO, | 
 | 421 | 			       GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel"); | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 422 | 	if (err) | 
 | 423 | 		goto err_gpio_tvout_sel; | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 424 | 	err = gpio_request_one(RX51_ECI_SW_GPIO, | 
 | 425 | 			       GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw"); | 
 | 426 | 	if (err) | 
 | 427 | 		goto err_gpio_eci_sw; | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 428 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 429 | 	rx51_snd_device = platform_device_alloc("soc-audio", -1); | 
 | 430 | 	if (!rx51_snd_device) { | 
 | 431 | 		err = -ENOMEM; | 
 | 432 | 		goto err1; | 
 | 433 | 	} | 
 | 434 |  | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 435 | 	platform_set_drvdata(rx51_snd_device, &rx51_sound_card); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 436 |  | 
 | 437 | 	err = platform_device_add(rx51_snd_device); | 
 | 438 | 	if (err) | 
 | 439 | 		goto err2; | 
 | 440 |  | 
 | 441 | 	return 0; | 
 | 442 | err2: | 
 | 443 | 	platform_device_put(rx51_snd_device); | 
 | 444 | err1: | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 445 | 	gpio_free(RX51_ECI_SW_GPIO); | 
 | 446 | err_gpio_eci_sw: | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 447 | 	gpio_free(RX51_TVOUT_SEL_GPIO); | 
 | 448 | err_gpio_tvout_sel: | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 449 |  | 
 | 450 | 	return err; | 
 | 451 | } | 
 | 452 |  | 
 | 453 | static void __exit rx51_soc_exit(void) | 
 | 454 | { | 
| Jarkko Nikula | 8c52311 | 2010-06-21 14:15:00 +0300 | [diff] [blame] | 455 | 	snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios), | 
 | 456 | 				rx51_av_jack_gpios); | 
 | 457 |  | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 458 | 	platform_device_unregister(rx51_snd_device); | 
| Jarkko Nikula | 31164c7 | 2011-02-14 17:20:21 +0200 | [diff] [blame] | 459 | 	gpio_free(RX51_ECI_SW_GPIO); | 
| Jarkko Nikula | 4eb54703 | 2010-06-21 14:14:59 +0300 | [diff] [blame] | 460 | 	gpio_free(RX51_TVOUT_SEL_GPIO); | 
| Jarkko Nikula | 49100c9 | 2010-05-05 11:14:22 +0300 | [diff] [blame] | 461 | } | 
 | 462 |  | 
 | 463 | module_init(rx51_soc_init); | 
 | 464 | module_exit(rx51_soc_exit); | 
 | 465 |  | 
 | 466 | MODULE_AUTHOR("Nokia Corporation"); | 
 | 467 | MODULE_DESCRIPTION("ALSA SoC Nokia RX-51"); | 
 | 468 | MODULE_LICENSE("GPL"); |