| OLD | NEW |
| 1 /* | 1 /* |
| 2 * rx51.c -- SoC audio for Nokia RX-51 | 2 * rx51.c -- SoC audio for Nokia RX-51 |
| 3 * | 3 * |
| 4 * Copyright (C) 2008 - 2009 Nokia Corporation | 4 * Copyright (C) 2008 - 2009 Nokia Corporation |
| 5 * | 5 * |
| 6 * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com> | 6 * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com> |
| 7 * Eduardo Valentin <eduardo.valentin@nokia.com> | 7 * Eduardo Valentin <eduardo.valentin@nokia.com> |
| 8 * Jarkko Nikula <jhnikula@gmail.com> | 8 * Jarkko Nikula <jhnikula@gmail.com> |
| 9 * | 9 * |
| 10 * This program is free software; you can redistribute it and/or | 10 * This program is free software; you can redistribute it and/or |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 * | 23 * |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include <linux/delay.h> | 26 #include <linux/delay.h> |
| 27 #include <linux/gpio.h> | 27 #include <linux/gpio.h> |
| 28 #include <linux/platform_device.h> | 28 #include <linux/platform_device.h> |
| 29 #include <sound/core.h> | 29 #include <sound/core.h> |
| 30 #include <sound/jack.h> | 30 #include <sound/jack.h> |
| 31 #include <sound/pcm.h> | 31 #include <sound/pcm.h> |
| 32 #include <sound/soc.h> | 32 #include <sound/soc.h> |
| 33 #include <sound/soc-dapm.h> | |
| 34 #include <plat/mcbsp.h> | 33 #include <plat/mcbsp.h> |
| 34 #include "../codecs/tpa6130a2.h" |
| 35 | 35 |
| 36 #include <asm/mach-types.h> | 36 #include <asm/mach-types.h> |
| 37 | 37 |
| 38 #include "omap-mcbsp.h" | 38 #include "omap-mcbsp.h" |
| 39 #include "omap-pcm.h" | 39 #include "omap-pcm.h" |
| 40 #include "../codecs/tlv320aic3x.h" | |
| 41 | 40 |
| 42 #define RX51_TVOUT_SEL_GPIO 40 | 41 #define RX51_TVOUT_SEL_GPIO 40 |
| 43 #define RX51_JACK_DETECT_GPIO 177 | 42 #define RX51_JACK_DETECT_GPIO 177 |
| 44 /* | 43 /* |
| 45 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This | 44 * 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 | 45 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c |
| 47 */ | 46 */ |
| 48 #define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) | 47 #define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) |
| 49 | 48 |
| 50 enum { | 49 enum { |
| 51 RX51_JACK_DISABLED, | 50 RX51_JACK_DISABLED, |
| 52 » RX51_JACK_TVOUT,» » /* tv-out */ | 51 » RX51_JACK_TVOUT,» » /* tv-out with stereo output */ |
| 52 » RX51_JACK_HP,» » » /* headphone: stereo output, no mic */ |
| 53 }; | 53 }; |
| 54 | 54 |
| 55 static int rx51_spk_func; | 55 static int rx51_spk_func; |
| 56 static int rx51_dmic_func; | 56 static int rx51_dmic_func; |
| 57 static int rx51_jack_func; | 57 static int rx51_jack_func; |
| 58 | 58 |
| 59 static void rx51_ext_control(struct snd_soc_codec *codec) | 59 static void rx51_ext_control(struct snd_soc_codec *codec) |
| 60 { | 60 { |
| 61 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 62 int hp = 0, tvout = 0; |
| 63 |
| 64 switch (rx51_jack_func) { |
| 65 case RX51_JACK_TVOUT: |
| 66 tvout = 1; |
| 67 case RX51_JACK_HP: |
| 68 hp = 1; |
| 69 break; |
| 70 } |
| 71 |
| 61 if (rx51_spk_func) | 72 if (rx51_spk_func) |
| 62 » » snd_soc_dapm_enable_pin(codec, "Ext Spk"); | 73 » » snd_soc_dapm_enable_pin(dapm, "Ext Spk"); |
| 63 else | 74 else |
| 64 » » snd_soc_dapm_disable_pin(codec, "Ext Spk"); | 75 » » snd_soc_dapm_disable_pin(dapm, "Ext Spk"); |
| 65 if (rx51_dmic_func) | 76 if (rx51_dmic_func) |
| 66 » » snd_soc_dapm_enable_pin(codec, "DMic"); | 77 » » snd_soc_dapm_enable_pin(dapm, "DMic"); |
| 67 else | 78 else |
| 68 » » snd_soc_dapm_disable_pin(codec, "DMic"); | 79 » » snd_soc_dapm_disable_pin(dapm, "DMic"); |
| 80 » if (hp) |
| 81 » » snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
| 82 » else |
| 83 » » snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
| 69 | 84 |
| 70 » gpio_set_value(RX51_TVOUT_SEL_GPIO, | 85 » gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); |
| 71 » » rx51_jack_func == RX51_JACK_TVOUT); | |
| 72 | 86 |
| 73 » snd_soc_dapm_sync(codec); | 87 » snd_soc_dapm_sync(dapm); |
| 74 } | 88 } |
| 75 | 89 |
| 76 static int rx51_startup(struct snd_pcm_substream *substream) | 90 static int rx51_startup(struct snd_pcm_substream *substream) |
| 77 { | 91 { |
| 78 struct snd_pcm_runtime *runtime = substream->runtime; | 92 struct snd_pcm_runtime *runtime = substream->runtime; |
| 79 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 93 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 80 struct snd_soc_codec *codec = rtd->codec; | 94 struct snd_soc_codec *codec = rtd->codec; |
| 81 | 95 |
| 82 snd_pcm_hw_constraint_minmax(runtime, | 96 snd_pcm_hw_constraint_minmax(runtime, |
| 83 SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); | 97 SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 struct snd_kcontrol *k, int event) | 160 struct snd_kcontrol *k, int event) |
| 147 { | 161 { |
| 148 if (SND_SOC_DAPM_EVENT_ON(event)) | 162 if (SND_SOC_DAPM_EVENT_ON(event)) |
| 149 gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1); | 163 gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1); |
| 150 else | 164 else |
| 151 gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0); | 165 gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0); |
| 152 | 166 |
| 153 return 0; | 167 return 0; |
| 154 } | 168 } |
| 155 | 169 |
| 170 static int rx51_hp_event(struct snd_soc_dapm_widget *w, |
| 171 struct snd_kcontrol *k, int event) |
| 172 { |
| 173 struct snd_soc_codec *codec = w->dapm->codec; |
| 174 |
| 175 if (SND_SOC_DAPM_EVENT_ON(event)) |
| 176 tpa6130a2_stereo_enable(codec, 1); |
| 177 else |
| 178 tpa6130a2_stereo_enable(codec, 0); |
| 179 |
| 180 return 0; |
| 181 } |
| 182 |
| 156 static int rx51_get_input(struct snd_kcontrol *kcontrol, | 183 static int rx51_get_input(struct snd_kcontrol *kcontrol, |
| 157 struct snd_ctl_elem_value *ucontrol) | 184 struct snd_ctl_elem_value *ucontrol) |
| 158 { | 185 { |
| 159 ucontrol->value.integer.value[0] = rx51_dmic_func; | 186 ucontrol->value.integer.value[0] = rx51_dmic_func; |
| 160 | 187 |
| 161 return 0; | 188 return 0; |
| 162 } | 189 } |
| 163 | 190 |
| 164 static int rx51_set_input(struct snd_kcontrol *kcontrol, | 191 static int rx51_set_input(struct snd_kcontrol *kcontrol, |
| 165 struct snd_ctl_elem_value *ucontrol) | 192 struct snd_ctl_elem_value *ucontrol) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 .name = "avdet-gpio", | 232 .name = "avdet-gpio", |
| 206 .report = SND_JACK_VIDEOOUT, | 233 .report = SND_JACK_VIDEOOUT, |
| 207 .invert = 1, | 234 .invert = 1, |
| 208 .debounce_time = 200, | 235 .debounce_time = 200, |
| 209 }, | 236 }, |
| 210 }; | 237 }; |
| 211 | 238 |
| 212 static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | 239 static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { |
| 213 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | 240 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), |
| 214 SND_SOC_DAPM_MIC("DMic", NULL), | 241 SND_SOC_DAPM_MIC("DMic", NULL), |
| 242 SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), |
| 243 }; |
| 244 |
| 245 static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = { |
| 246 SND_SOC_DAPM_SPK("Earphone", NULL), |
| 215 }; | 247 }; |
| 216 | 248 |
| 217 static const struct snd_soc_dapm_route audio_map[] = { | 249 static const struct snd_soc_dapm_route audio_map[] = { |
| 218 {"Ext Spk", NULL, "HPLOUT"}, | 250 {"Ext Spk", NULL, "HPLOUT"}, |
| 219 {"Ext Spk", NULL, "HPROUT"}, | 251 {"Ext Spk", NULL, "HPROUT"}, |
| 252 {"Headphone Jack", NULL, "LLOUT"}, |
| 253 {"Headphone Jack", NULL, "RLOUT"}, |
| 220 | 254 |
| 221 {"DMic Rate 64", NULL, "Mic Bias 2V"}, | 255 {"DMic Rate 64", NULL, "Mic Bias 2V"}, |
| 222 {"Mic Bias 2V", NULL, "DMic"}, | 256 {"Mic Bias 2V", NULL, "DMic"}, |
| 223 }; | 257 }; |
| 224 | 258 |
| 259 static const struct snd_soc_dapm_route audio_mapb[] = { |
| 260 {"b LINE2R", NULL, "MONO_LOUT"}, |
| 261 {"Earphone", NULL, "b HPLOUT"}, |
| 262 }; |
| 263 |
| 225 static const char *spk_function[] = {"Off", "On"}; | 264 static const char *spk_function[] = {"Off", "On"}; |
| 226 static const char *input_function[] = {"ADC", "Digital Mic"}; | 265 static const char *input_function[] = {"ADC", "Digital Mic"}; |
| 227 static const char *jack_function[] = {"Off", "TV-OUT"}; | 266 static const char *jack_function[] = {"Off", "TV-OUT", "Headphone"}; |
| 228 | 267 |
| 229 static const struct soc_enum rx51_enum[] = { | 268 static const struct soc_enum rx51_enum[] = { |
| 230 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 269 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
| 231 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | 270 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), |
| 232 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), | 271 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), |
| 233 }; | 272 }; |
| 234 | 273 |
| 235 static const struct snd_kcontrol_new aic34_rx51_controls[] = { | 274 static const struct snd_kcontrol_new aic34_rx51_controls[] = { |
| 236 SOC_ENUM_EXT("Speaker Function", rx51_enum[0], | 275 SOC_ENUM_EXT("Speaker Function", rx51_enum[0], |
| 237 rx51_get_spk, rx51_set_spk), | 276 rx51_get_spk, rx51_set_spk), |
| 238 SOC_ENUM_EXT("Input Select", rx51_enum[1], | 277 SOC_ENUM_EXT("Input Select", rx51_enum[1], |
| 239 rx51_get_input, rx51_set_input), | 278 rx51_get_input, rx51_set_input), |
| 240 SOC_ENUM_EXT("Jack Function", rx51_enum[2], | 279 SOC_ENUM_EXT("Jack Function", rx51_enum[2], |
| 241 rx51_get_jack, rx51_set_jack), | 280 rx51_get_jack, rx51_set_jack), |
| 242 }; | 281 }; |
| 243 | 282 |
| 283 static const struct snd_kcontrol_new aic34_rx51_controlsb[] = { |
| 284 SOC_DAPM_PIN_SWITCH("Earphone"), |
| 285 }; |
| 286 |
| 244 static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | 287 static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) |
| 245 { | 288 { |
| 246 struct snd_soc_codec *codec = rtd->codec; | 289 struct snd_soc_codec *codec = rtd->codec; |
| 290 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 247 int err; | 291 int err; |
| 248 | 292 |
| 249 /* Set up NC codec pins */ | 293 /* Set up NC codec pins */ |
| 250 » snd_soc_dapm_nc_pin(codec, "MIC3L"); | 294 » snd_soc_dapm_nc_pin(dapm, "MIC3L"); |
| 251 » snd_soc_dapm_nc_pin(codec, "MIC3R"); | 295 » snd_soc_dapm_nc_pin(dapm, "MIC3R"); |
| 252 » snd_soc_dapm_nc_pin(codec, "LINE1R"); | 296 » snd_soc_dapm_nc_pin(dapm, "LINE1R"); |
| 253 | 297 |
| 254 /* Add RX-51 specific controls */ | 298 /* Add RX-51 specific controls */ |
| 255 err = snd_soc_add_controls(codec, aic34_rx51_controls, | 299 err = snd_soc_add_controls(codec, aic34_rx51_controls, |
| 256 ARRAY_SIZE(aic34_rx51_controls)); | 300 ARRAY_SIZE(aic34_rx51_controls)); |
| 257 if (err < 0) | 301 if (err < 0) |
| 258 return err; | 302 return err; |
| 259 | 303 |
| 260 /* Add RX-51 specific widgets */ | 304 /* Add RX-51 specific widgets */ |
| 261 » snd_soc_dapm_new_controls(codec, aic34_dapm_widgets, | 305 » snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets, |
| 262 ARRAY_SIZE(aic34_dapm_widgets)); | 306 ARRAY_SIZE(aic34_dapm_widgets)); |
| 263 | 307 |
| 264 /* Set up RX-51 specific audio path audio_map */ | 308 /* Set up RX-51 specific audio path audio_map */ |
| 265 » snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 309 » snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
| 266 | 310 |
| 267 » snd_soc_dapm_sync(codec); | 311 » err = tpa6130a2_add_controls(codec); |
| 312 » if (err < 0) |
| 313 » » return err; |
| 314 » snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); |
| 315 |
| 316 » snd_soc_dapm_sync(dapm); |
| 268 | 317 |
| 269 /* AV jack detection */ | 318 /* AV jack detection */ |
| 270 err = snd_soc_jack_new(codec, "AV Jack", | 319 err = snd_soc_jack_new(codec, "AV Jack", |
| 271 SND_JACK_VIDEOOUT, &rx51_av_jack); | 320 SND_JACK_VIDEOOUT, &rx51_av_jack); |
| 272 if (err) | 321 if (err) |
| 273 return err; | 322 return err; |
| 274 err = snd_soc_jack_add_gpios(&rx51_av_jack, | 323 err = snd_soc_jack_add_gpios(&rx51_av_jack, |
| 275 ARRAY_SIZE(rx51_av_jack_gpios), | 324 ARRAY_SIZE(rx51_av_jack_gpios), |
| 276 rx51_av_jack_gpios); | 325 rx51_av_jack_gpios); |
| 277 | 326 |
| 278 return err; | 327 return err; |
| 279 } | 328 } |
| 280 | 329 |
| 330 static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm) |
| 331 { |
| 332 int err; |
| 333 |
| 334 err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb, |
| 335 ARRAY_SIZE(aic34_rx51_controlsb)); |
| 336 if (err < 0) |
| 337 return err; |
| 338 |
| 339 err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb, |
| 340 ARRAY_SIZE(aic34_dapm_widgetsb)); |
| 341 if (err < 0) |
| 342 return 0; |
| 343 |
| 344 return snd_soc_dapm_add_routes(dapm, audio_mapb, |
| 345 ARRAY_SIZE(audio_mapb)); |
| 346 } |
| 347 |
| 281 /* Digital audio interface glue - connects codec <--> CPU */ | 348 /* Digital audio interface glue - connects codec <--> CPU */ |
| 282 static struct snd_soc_dai_link rx51_dai[] = { | 349 static struct snd_soc_dai_link rx51_dai[] = { |
| 283 { | 350 { |
| 284 .name = "TLV320AIC34", | 351 .name = "TLV320AIC34", |
| 285 .stream_name = "AIC34", | 352 .stream_name = "AIC34", |
| 286 .cpu_dai_name = "omap-mcbsp-dai.1", | 353 .cpu_dai_name = "omap-mcbsp-dai.1", |
| 287 .codec_dai_name = "tlv320aic3x-hifi", | 354 .codec_dai_name = "tlv320aic3x-hifi", |
| 288 .platform_name = "omap-pcm-audio", | 355 .platform_name = "omap-pcm-audio", |
| 289 .codec_name = "tlv320aic3x-codec.2-0018", | 356 .codec_name = "tlv320aic3x-codec.2-0018", |
| 290 .init = rx51_aic34_init, | 357 .init = rx51_aic34_init, |
| 291 .ops = &rx51_ops, | 358 .ops = &rx51_ops, |
| 292 }, | 359 }, |
| 293 }; | 360 }; |
| 294 | 361 |
| 362 struct snd_soc_aux_dev rx51_aux_dev[] = { |
| 363 { |
| 364 .name = "TLV320AIC34b", |
| 365 .codec_name = "tlv320aic3x-codec.2-0019", |
| 366 .init = rx51_aic34b_init, |
| 367 }, |
| 368 }; |
| 369 |
| 370 static struct snd_soc_codec_conf rx51_codec_conf[] = { |
| 371 { |
| 372 .dev_name = "tlv320aic3x-codec.2-0019", |
| 373 .name_prefix = "b", |
| 374 }, |
| 375 }; |
| 376 |
| 295 /* Audio card */ | 377 /* Audio card */ |
| 296 static struct snd_soc_card rx51_sound_card = { | 378 static struct snd_soc_card rx51_sound_card = { |
| 297 .name = "RX-51", | 379 .name = "RX-51", |
| 298 .dai_link = rx51_dai, | 380 .dai_link = rx51_dai, |
| 299 .num_links = ARRAY_SIZE(rx51_dai), | 381 .num_links = ARRAY_SIZE(rx51_dai), |
| 382 .aux_dev = rx51_aux_dev, |
| 383 .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), |
| 384 .codec_conf = rx51_codec_conf, |
| 385 .num_configs = ARRAY_SIZE(rx51_codec_conf), |
| 300 }; | 386 }; |
| 301 | 387 |
| 302 static struct platform_device *rx51_snd_device; | 388 static struct platform_device *rx51_snd_device; |
| 303 | 389 |
| 304 static int __init rx51_soc_init(void) | 390 static int __init rx51_soc_init(void) |
| 305 { | 391 { |
| 306 int err; | 392 int err; |
| 307 | 393 |
| 308 if (!machine_is_nokia_rx51()) | 394 if (!machine_is_nokia_rx51()) |
| 309 return -ENODEV; | 395 return -ENODEV; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 platform_device_unregister(rx51_snd_device); | 429 platform_device_unregister(rx51_snd_device); |
| 344 gpio_free(RX51_TVOUT_SEL_GPIO); | 430 gpio_free(RX51_TVOUT_SEL_GPIO); |
| 345 } | 431 } |
| 346 | 432 |
| 347 module_init(rx51_soc_init); | 433 module_init(rx51_soc_init); |
| 348 module_exit(rx51_soc_exit); | 434 module_exit(rx51_soc_exit); |
| 349 | 435 |
| 350 MODULE_AUTHOR("Nokia Corporation"); | 436 MODULE_AUTHOR("Nokia Corporation"); |
| 351 MODULE_DESCRIPTION("ALSA SoC Nokia RX-51"); | 437 MODULE_DESCRIPTION("ALSA SoC Nokia RX-51"); |
| 352 MODULE_LICENSE("GPL"); | 438 MODULE_LICENSE("GPL"); |
| OLD | NEW |