summaryrefslogtreecommitdiff
path: root/sound/soc/tegra/tegra_soc_controls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra_soc_controls.c')
-rw-r--r--sound/soc/tegra/tegra_soc_controls.c431
1 files changed, 69 insertions, 362 deletions
diff --git a/sound/soc/tegra/tegra_soc_controls.c b/sound/soc/tegra/tegra_soc_controls.c
index 04ffd880ed0e..bd948509df62 100644
--- a/sound/soc/tegra/tegra_soc_controls.c
+++ b/sound/soc/tegra/tegra_soc_controls.c
@@ -1,7 +1,7 @@
/*
* tegra_soc_controls.c -- alsa controls for tegra SoC
*
- * Copyright (c) 2010, NVIDIA Corporation.
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,259 +18,14 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <linux/gpio.h>
-#include <sound/soc-dapm.h>
-#include <linux/regulator/consumer.h>
-#include <mach/audio.h>
-
#include "tegra_soc.h"
-#define TEGRA_HP 0
-#define TEGRA_MIC 1
-#define TEGRA_LINE 2
-#define TEGRA_HEADSET 3
-#define TEGRA_HP_OFF 4
-
-#define TEGRA_LINEOUT_ON 0
-#define TEGRA_LINEOUT_OFF 1
-
-#define TEGRA_INT_SPK_ON 0
-#define TEGRA_INT_SPK_OFF 1
-
-extern struct wired_jack_conf tegra_wired_jack_conf;
-
-static struct tegra_audio_data *audio_data;
-
-static int tegra_jack_func;
-static int tegra_lineout_func;
-static int tegra_spk_func;
-
-static void tegra_ext_control(struct snd_soc_codec *codec)
-{
- /* set up jack connection */
- switch (tegra_jack_func) {
- case TEGRA_HP:
- /* set = unmute headphone */
- snd_soc_dapm_enable_pin(codec, "Mic Jack");
- snd_soc_dapm_disable_pin(codec, "Line Jack");
- snd_soc_dapm_enable_pin(codec, "Headphone Jack");
- snd_soc_dapm_disable_pin(codec, "Headset Jack");
- break;
- case TEGRA_MIC:
- /* reset = mute headphone */
- snd_soc_dapm_enable_pin(codec, "Mic Jack");
- snd_soc_dapm_disable_pin(codec, "Line Jack");
- snd_soc_dapm_disable_pin(codec, "Headphone Jack");
- snd_soc_dapm_disable_pin(codec, "Headset Jack");
- break;
- case TEGRA_LINE:
- snd_soc_dapm_disable_pin(codec, "Mic Jack");
- snd_soc_dapm_enable_pin(codec, "Line Jack");
- snd_soc_dapm_disable_pin(codec, "Headphone Jack");
- snd_soc_dapm_disable_pin(codec, "Headset Jack");
- break;
- case TEGRA_HEADSET:
- snd_soc_dapm_enable_pin(codec, "Mic Jack");
- snd_soc_dapm_disable_pin(codec, "Line Jack");
- snd_soc_dapm_disable_pin(codec, "Headphone Jack");
- snd_soc_dapm_enable_pin(codec, "Headset Jack");
- break;
- }
-
-
- if (tegra_lineout_func == TEGRA_LINEOUT_ON) {
- snd_soc_dapm_enable_pin(codec, "Lineout");
- } else {
- snd_soc_dapm_disable_pin(codec, "Lineout");
- }
-
- if (tegra_spk_func == TEGRA_INT_SPK_ON) {
- snd_soc_dapm_enable_pin(codec, "Int Spk");
- if (tegra_wired_jack_conf.amp_reg &&
- !tegra_wired_jack_conf.amp_reg_enabled) {
- regulator_enable(tegra_wired_jack_conf.amp_reg);
- tegra_wired_jack_conf.amp_reg_enabled = 1;
- }
- } else {
- snd_soc_dapm_disable_pin(codec, "Int Spk");
- if (tegra_wired_jack_conf.amp_reg &&
- tegra_wired_jack_conf.amp_reg_enabled) {
- regulator_disable(tegra_wired_jack_conf.amp_reg);
- tegra_wired_jack_conf.amp_reg_enabled = 0;
- }
- }
-
- /* signal a DAPM event */
- snd_soc_dapm_sync(codec);
-}
-
-static int tegra_get_jack(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = tegra_jack_func;
- return 0;
-}
-
-static int tegra_set_jack(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- if (tegra_jack_func == ucontrol->value.integer.value[0])
- return 0;
-
- tegra_jack_func = ucontrol->value.integer.value[0];
- tegra_ext_control(codec);
- return 1;
-}
-
-static int tegra_get_lineout(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = tegra_lineout_func;
- return 0;
-}
-
-static int tegra_set_lineout(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
- if (tegra_lineout_func == ucontrol->value.integer.value[0])
- return 0;
-
- tegra_lineout_func = ucontrol->value.integer.value[0];
- tegra_ext_control(codec);
- return 1;
-}
-
-static int tegra_get_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] = tegra_spk_func;
- return 0;
-}
-
-static int tegra_set_spk(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
-
- if (tegra_spk_func == ucontrol->value.integer.value[0])
- return 0;
-
- tegra_spk_func = ucontrol->value.integer.value[0];
- tegra_ext_control(codec);
- return 1;
-}
-
-static int tegra_dapm_event_int_spk(struct snd_soc_dapm_widget* w,
- struct snd_kcontrol* k, int event)
-{
- if (tegra_wired_jack_conf.en_spkr != -1)
- gpio_set_value_cansleep(tegra_wired_jack_conf.en_spkr,
- SND_SOC_DAPM_EVENT_ON(event));
-
- return 0;
-}
-
-static int tegra_dapm_event_int_mic(struct snd_soc_dapm_widget* w,
- struct snd_kcontrol* k, int event)
-{
- if (tegra_wired_jack_conf.en_mic_int != -1)
- gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_int,
- SND_SOC_DAPM_EVENT_ON(event));
-
- if (tegra_wired_jack_conf.en_mic_ext != -1)
- gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_ext,
- !(SND_SOC_DAPM_EVENT_ON(event)));
-
- return 0;
-}
-
-static int tegra_dapm_event_ext_mic(struct snd_soc_dapm_widget* w,
- struct snd_kcontrol* k, int event)
-{
- if (tegra_wired_jack_conf.en_mic_ext != -1)
- gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_ext,
- SND_SOC_DAPM_EVENT_ON(event));
-
- if (tegra_wired_jack_conf.en_mic_int != -1)
- gpio_set_value_cansleep(tegra_wired_jack_conf.en_mic_int,
- !(SND_SOC_DAPM_EVENT_ON(event)));
-
- return 0;
-}
-
-/*tegra machine dapm widgets */
-static const struct snd_soc_dapm_widget tegra_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", tegra_dapm_event_ext_mic),
- SND_SOC_DAPM_MIC("Int Mic", tegra_dapm_event_int_mic),
- SND_SOC_DAPM_SPK("Lineout", NULL),
- SND_SOC_DAPM_SPK("Int Spk", tegra_dapm_event_int_spk),
- SND_SOC_DAPM_LINE("Line Jack", NULL),
- SND_SOC_DAPM_HP("Headset Jack", NULL),
-};
-
-/* Tegra machine audio map (connections to the codec pins) */
-static const struct snd_soc_dapm_route audio_map[] = {
-
- /* headset Jack - in = micin, out = LHPOUT*/
- {"Headset Jack", NULL, "HPOUTL"},
- {"Headset Jack", NULL, "HPOUTR"},
-
- /* headphone connected to LHPOUT1, RHPOUT1 */
- {"Headphone Jack", NULL, "HPOUTR"},
- {"Headphone Jack", NULL, "HPOUTL"},
-
- /* build-in speaker connected to LON/P RON/P */
- {"Int Spk", NULL, "RON"},
- {"Int Spk", NULL, "ROP"},
- {"Int Spk", NULL, "LON"},
- {"Int Spk", NULL, "LOP"},
-
- /* lineout connected to LINEOUTR and LINEOUTL */
- {"Lineout", NULL, "LINEOUTR"},
- {"Lineout", NULL, "LINEOUTL"},
-
- /* external mic is stero */
- {"IN1L", NULL, "Mic Jack"},
- {"IN1R", NULL, "Mic Jack"},
-
- /* internal mic is mono */
- {"IN1R", NULL, "Int Mic"},
-
- {"IN3L", NULL, "Line Jack"},
- {"IN3R", NULL, "Line Jack"},
-};
-
-static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset",
- "Off"
- };
-static const char *lineout_function[] = {"On", "Off"};
-static const char *spk_function[] = {"On", "Off"};
-
-static const struct soc_enum tegra_enum[] = {
- SOC_ENUM_SINGLE_EXT(5, jack_function),
- SOC_ENUM_SINGLE_EXT(2, lineout_function),
- SOC_ENUM_SINGLE_EXT(2, spk_function),
-};
-
-static const struct snd_kcontrol_new tegra_controls[] = {
- SOC_ENUM_EXT("Jack Function", tegra_enum[0], tegra_get_jack,
- tegra_set_jack),
- SOC_ENUM_EXT("Lineout Function", tegra_enum[1], tegra_get_lineout,
- tegra_set_lineout),
- SOC_ENUM_EXT("Speaker Function", tegra_enum[2], tegra_get_spk,
- tegra_set_spk),
-};
-
-static void tegra_audio_route(int device_new, int is_call_mode_new)
+static void tegra_audio_route(struct tegra_audio_data* audio_data,
+ int device_new, int is_call_mode_new)
{
int play_device_new = device_new & TEGRA_AUDIO_DEVICE_OUT_ALL;
int capture_device_new = device_new & TEGRA_AUDIO_DEVICE_IN_ALL;
+ int codec_con = audio_data->codec_con;
int is_bt_sco_mode =
(play_device_new & TEGRA_AUDIO_DEVICE_OUT_BT_SCO) ||
(capture_device_new & TEGRA_AUDIO_DEVICE_OUT_BT_SCO);
@@ -279,51 +34,46 @@ static void tegra_audio_route(int device_new, int is_call_mode_new)
(audio_data->capture_device & TEGRA_AUDIO_DEVICE_OUT_BT_SCO);
if (play_device_new != audio_data->play_device) {
- if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADPHONE) {
- tegra_jack_func = TEGRA_HP;
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- }
- else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADSET) {
- tegra_jack_func = TEGRA_HEADSET;
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- }
- else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_LINE) {
- tegra_jack_func = TEGRA_LINE;
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- }
+ codec_con &= ~(TEGRA_HEADPHONE | TEGRA_LINEOUT |
+ TEGRA_SPK | TEGRA_EAR_SPK | TEGRA_HEADSET);
- if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_SPEAKER) {
- tegra_lineout_func = TEGRA_LINEOUT_OFF;
- tegra_spk_func = TEGRA_INT_SPK_ON;
- }
- else if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_EAR_SPEAKER) {
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- tegra_lineout_func = TEGRA_LINEOUT_ON;
- }
- else {
- tegra_lineout_func = TEGRA_LINEOUT_OFF;
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- }
- tegra_ext_control(audio_data->codec);
+ if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADPHONE)
+ codec_con |= TEGRA_HEADPHONE;
+
+ if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_LINE)
+ codec_con |= TEGRA_LINEOUT;
+
+ if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_SPEAKER)
+ codec_con |= TEGRA_SPK;
+
+ if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_EAR_SPEAKER)
+ codec_con |= TEGRA_EAR_SPK;
+
+ if (play_device_new & TEGRA_AUDIO_DEVICE_OUT_HEADSET)
+ codec_con |= TEGRA_HEADSET;
+
+ tegra_ext_control(audio_data->codec, codec_con);
audio_data->play_device = play_device_new;
}
if (capture_device_new != audio_data->capture_device) {
+ codec_con &= ~(TEGRA_INT_MIC | TEGRA_EXT_MIC |
+ TEGRA_LINEIN | TEGRA_HEADSET);
+
if (capture_device_new & (TEGRA_AUDIO_DEVICE_IN_BUILTIN_MIC |
- TEGRA_AUDIO_DEVICE_IN_MIC |
- TEGRA_AUDIO_DEVICE_IN_BACK_MIC)) {
- if ((tegra_jack_func != TEGRA_HP) &&
- (tegra_jack_func != TEGRA_HEADSET)) {
- tegra_jack_func = TEGRA_MIC;
- }
- }
- else if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_HEADSET) {
- tegra_jack_func = TEGRA_HEADSET;
- }
- else if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_LINE) {
- tegra_jack_func = TEGRA_LINE;
- }
- tegra_ext_control(audio_data->codec);
+ TEGRA_AUDIO_DEVICE_IN_BACK_MIC))
+ codec_con |= TEGRA_INT_MIC;
+
+ if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_MIC)
+ codec_con |= TEGRA_EXT_MIC;
+
+ if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_LINE)
+ codec_con |= TEGRA_LINEIN;
+
+ if (capture_device_new & TEGRA_AUDIO_DEVICE_IN_HEADSET)
+ codec_con |= TEGRA_HEADSET;
+
+ tegra_ext_control(audio_data->codec, codec_con);
audio_data->capture_device = capture_device_new;
}
@@ -362,6 +112,8 @@ static int tegra_play_route_info(struct snd_kcontrol *kcontrol,
static int tegra_play_route_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
ucontrol->value.integer.value[0] = TEGRA_AUDIO_DEVICE_NONE;
if (audio_data) {
ucontrol->value.integer.value[0] = audio_data->play_device;
@@ -373,12 +125,14 @@ static int tegra_play_route_get(struct snd_kcontrol *kcontrol,
static int tegra_play_route_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
if (audio_data) {
int play_device_new = ucontrol->value.integer.value[0] &
TEGRA_AUDIO_DEVICE_OUT_ALL;
if (audio_data->play_device != play_device_new) {
- tegra_audio_route(
+ tegra_audio_route(audio_data,
play_device_new | audio_data->capture_device,
audio_data->is_call_mode);
return 1;
@@ -411,6 +165,8 @@ static int tegra_capture_route_info(struct snd_kcontrol *kcontrol,
static int tegra_capture_route_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
ucontrol->value.integer.value[0] = TEGRA_AUDIO_DEVICE_NONE;
if (audio_data) {
ucontrol->value.integer.value[0] = audio_data->capture_device;
@@ -422,12 +178,14 @@ static int tegra_capture_route_get(struct snd_kcontrol *kcontrol,
static int tegra_capture_route_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
if (audio_data) {
int capture_device_new = ucontrol->value.integer.value[0] &
TEGRA_AUDIO_DEVICE_IN_ALL;
if (audio_data->capture_device != capture_device_new) {
- tegra_audio_route(
+ tegra_audio_route(audio_data,
audio_data->play_device | capture_device_new,
audio_data->is_call_mode);
return 1;
@@ -460,6 +218,8 @@ static int tegra_call_mode_info(struct snd_kcontrol *kcontrol,
static int tegra_call_mode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
ucontrol->value.integer.value[0] = TEGRA_AUDIO_DEVICE_NONE;
if (audio_data) {
ucontrol->value.integer.value[0] = audio_data->is_call_mode;
@@ -471,11 +231,13 @@ static int tegra_call_mode_get(struct snd_kcontrol *kcontrol,
static int tegra_call_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct tegra_audio_data* audio_data = snd_kcontrol_chip(kcontrol);
+
if (audio_data) {
int is_call_mode_new = ucontrol->value.integer.value[0];
if (audio_data->is_call_mode != is_call_mode_new) {
- tegra_audio_route(
+ tegra_audio_route(audio_data,
audio_data->play_device |
audio_data->capture_device,
is_call_mode_new);
@@ -498,81 +260,26 @@ struct snd_kcontrol_new tegra_call_mode_control = {
int tegra_controls_init(struct snd_soc_codec *codec)
{
+ struct tegra_audio_data* audio_data = codec->socdev->codec_data;
int err;
- if (codec == NULL)
- return -ENODEV;
+ /* Add play route control */
+ err = snd_ctl_add(codec->card,
+ snd_ctl_new1(&tegra_play_route_control, audio_data));
+ if (err < 0)
+ return err;
- if (!audio_data) {
- audio_data = kzalloc(sizeof(*audio_data), GFP_KERNEL);
- if (!audio_data) {
- pr_err("failed to allocate tegra_audio_data \n");
- return -ENOMEM;
- }
+ /* Add capture route control */
+ err = snd_ctl_add(codec->card,
+ snd_ctl_new1(&tegra_capture_route_control, audio_data));
+ if (err < 0)
+ return err;
- /* Add tegra specific controls */
- err = snd_soc_add_controls(codec, tegra_controls,
- ARRAY_SIZE(tegra_controls));
- if (err < 0)
- goto fail;
-
- /* Add tegra specific widgets */
- snd_soc_dapm_new_controls(codec, tegra_dapm_widgets,
- ARRAY_SIZE(tegra_dapm_widgets));
-
- /* Set up tegra specific audio path audio_map */
- snd_soc_dapm_add_routes(codec, audio_map,
- ARRAY_SIZE(audio_map));
-
- audio_data->codec = codec;
- /* Add play route control */
- err = snd_ctl_add(codec->card,
- snd_ctl_new1(&tegra_play_route_control, NULL));
- if (err < 0)
- goto fail;
-
- /* Add capture route control */
- err = snd_ctl_add(codec->card,
- snd_ctl_new1(&tegra_capture_route_control, NULL));
- if (err < 0)
- goto fail;
-
- /* Add call mode switch control */
- err = snd_ctl_add(codec->card,
- snd_ctl_new1(&tegra_call_mode_control, NULL));
- if (err < 0)
- goto fail;
-
- /* Add jack detection */
- err = tegra_jack_init(codec);
- if (err < 0)
- goto fail;
-
- /* Default to HP output */
- tegra_jack_func = TEGRA_HP;
- tegra_lineout_func = TEGRA_LINEOUT_ON;
- tegra_spk_func = TEGRA_INT_SPK_OFF;
- tegra_ext_control(codec);
-
- snd_soc_dapm_sync(codec);
- }
+ /* Add call mode switch control */
+ err = snd_ctl_add(codec->card,
+ snd_ctl_new1(&tegra_call_mode_control, audio_data));
+ if (err < 0)
+ return err;
return 0;
-
-fail:
- if (audio_data) {
- kfree(audio_data);
- audio_data = 0;
- }
- return err;
-}
-
-void tegra_controls_exit(void)
-{
- tegra_jack_exit();
-
- if (audio_data) {
- kfree(audio_data);
- audio_data = 0;
- }
}