[ARM] cpcap-audio: enable low-power standby mode
authorJames Wylder <james.wylder@motorola.com>
Tue, 14 Sep 2010 03:19:01 +0000 (22:19 -0500)
committerColin Cross <ccross@android.com>
Thu, 7 Oct 2010 00:01:27 +0000 (17:01 -0700)
-- add CPCAP_AUDIO_OUT_STANDBY definition, extended ioctl interface to support
   for selecting new CPCAP_AUDIO_OUT_STANDBY output id;
-- manage VAUDIO through balanced calls to regulator_set_mode() initialize
   audio speaker to off.

Signed-off-by: Iliyan Malchev <malchev@google.com>
drivers/mfd/cpcap-audio-core.c
drivers/mfd/tegra-cpcap-audio.c
include/linux/cpcap_audio.h

index c854076a3bcb057cb4ea91c2d17211230255171e..d791c395e64d9e72f3b8a6ee651a616dac41c21e 100644 (file)
@@ -934,7 +934,7 @@ static void cpcap_audio_configure_input(struct cpcap_audio_state *state,
 
 static void cpcap_audio_configure_power(int power)
 {
-       static int previous_power = -1;
+       static int previous_power;
 
        pr_debug("%s() called with power= %d\n", __func__, power);
 
index 1c2de01398a997431602c32abb4f9b48f47c15f0..543fe7ef8ef8987550649a8530b3811ab45489bf 100644 (file)
 
 static struct cpcap_device *cpcap;
 static struct cpcap_audio_platform_data *pdata;
-static unsigned current_output = CPCAP_AUDIO_OUT_SPEAKER;
-static unsigned current_input  = -1U; /* none */
+static struct cpcap_audio_stream current_output = {
+       .id     = CPCAP_AUDIO_OUT_SPEAKER,
+};
+static struct cpcap_audio_stream current_input = {
+       .id     = CPCAP_AUDIO_IN_MIC1,
+};
 
 static int cpcap_audio_ctl_open(struct inode *inode, struct file *file)
 {
@@ -50,6 +54,111 @@ static int cpcap_audio_ctl_release(struct inode *inode, struct file *file)
 
 static DEFINE_MUTEX(cpcap_lock);
 
+static void tegra_setup_audio_output_off(void)
+{
+       /* turn off the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 0);
+       gpio_direction_output(pdata->headset_gpio, 0);
+
+       if (!current_input.on) {
+               pdata->state->codec_mute = CPCAP_AUDIO_CODEC_MUTE;
+               pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE;
+               pdata->state->codec_mode = CPCAP_AUDIO_CODEC_OFF;
+               pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_OFF;
+       }
+
+       pdata->state->stdac_primary_speaker = CPCAP_AUDIO_OUT_NONE;
+       pdata->state->stdac_secondary_speaker = CPCAP_AUDIO_OUT_NONE;
+       cpcap_audio_set_audio_state(pdata->state);
+}
+
+static void tegra_setup_audio_out_speaker_on(void)
+{
+       /* turn off the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 0);
+       gpio_direction_output(pdata->headset_gpio, 0);
+
+       pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
+       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
+       pdata->state->stdac_primary_speaker = CPCAP_AUDIO_OUT_LOUDSPEAKER;
+       pdata->state->stdac_secondary_speaker = CPCAP_AUDIO_OUT_LINEOUT;
+       cpcap_audio_set_audio_state(pdata->state);
+
+       /* turn on the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 1);
+       gpio_direction_output(pdata->headset_gpio, 0);
+}
+
+static void tegra_setup_audio_out_headset_on(void)
+{
+       /* turn off the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 0);
+       gpio_direction_output(pdata->headset_gpio, 0);
+
+       pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
+       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
+       pdata->state->stdac_primary_speaker = CPCAP_AUDIO_OUT_STEREO_HEADSET;
+       pdata->state->stdac_secondary_speaker = CPCAP_AUDIO_OUT_LINEOUT;
+       cpcap_audio_set_audio_state(pdata->state);
+
+       /* turn on the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 0);
+       gpio_direction_output(pdata->headset_gpio, 1);
+}
+
+static void tegra_setup_audio_out_headset_and_speaker_on(void)
+{
+       /* turn off the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 0);
+       gpio_direction_output(pdata->headset_gpio, 0);
+
+       pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
+       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
+       pdata->state->stdac_primary_speaker = CPCAP_AUDIO_OUT_STEREO_HEADSET;
+       pdata->state->stdac_secondary_speaker = CPCAP_AUDIO_OUT_LINEOUT;
+       cpcap_audio_set_audio_state(pdata->state);
+
+       /* turn on the amplifier */
+       gpio_direction_output(pdata->speaker_gpio, 1);
+       gpio_direction_output(pdata->headset_gpio, 1);
+}
+
+static void tegra_setup_audio_in_mute(void)
+{
+       if (!current_output.on) {
+               pdata->state->codec_mute = CPCAP_AUDIO_CODEC_MUTE;
+               pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE;
+               pdata->state->codec_mode = CPCAP_AUDIO_CODEC_OFF;
+               pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_OFF;
+       }
+
+       pdata->state->microphone = CPCAP_AUDIO_IN_NONE;
+
+       cpcap_audio_set_audio_state(pdata->state);
+}
+
+static void tegra_setup_audio_in_handset_on(void)
+{
+       pdata->state->codec_mute = CPCAP_AUDIO_CODEC_UNMUTE;
+       pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_UNMUTE;
+       pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
+       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
+
+       pdata->state->microphone = CPCAP_AUDIO_IN_HANDSET;
+       cpcap_audio_set_audio_state(pdata->state);
+}
+
+static void tegra_setup_audio_in_headset_on(void)
+{
+       pdata->state->codec_mute = CPCAP_AUDIO_CODEC_UNMUTE;
+       pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_UNMUTE;
+       pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
+       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
+
+       pdata->state->microphone = CPCAP_AUDIO_IN_HEADSET;
+       cpcap_audio_set_audio_state(pdata->state);
+}
+
 static long cpcap_audio_ctl_ioctl(struct file *file, unsigned int cmd,
                        unsigned long arg)
 {
@@ -75,67 +184,60 @@ static long cpcap_audio_ctl_ioctl(struct file *file, unsigned int cmd,
                case CPCAP_AUDIO_OUT_SPEAKER:
                        pr_info("%s: setting output path to speaker\n",
                                        __func__);
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_NONE;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       if (!out.on) {
-                               if (pdata->speaker_gpio >= 0)
-                                       gpio_direction_output(
-                                               pdata->speaker_gpio, 0);
-                               break;
-                       }
-
-                       pr_info("%s: enable speaker\n", __func__);
-
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_LOUDSPEAKER;
-                       gpio_direction_output(pdata->headset_gpio, 0);
-                       gpio_direction_output(pdata->speaker_gpio, 1);
+                       if (out.on)
+                               tegra_setup_audio_out_speaker_on();
+                       else
+                               tegra_setup_audio_output_off();
+                       current_output = out;
                        break;
                case CPCAP_AUDIO_OUT_HEADSET:
                        pr_info("%s: setting output path to headset\n",
-                                       __func__);
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_NONE;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       if (!out.on) {
-                               if (pdata->headset_gpio >= 0)
-                                       gpio_direction_output(
-                                               pdata->headset_gpio, 0);
-                               break;
-                       }
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_STEREO_HEADSET;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       gpio_direction_output(pdata->speaker_gpio, 0);
-                       gpio_direction_output(pdata->headset_gpio, 1);
+                                       __func__);;
+                       if (out.on)
+                               tegra_setup_audio_out_headset_on();
+                       else
+                               tegra_setup_audio_output_off();
+                       current_output = out;
                        break;
                case CPCAP_AUDIO_OUT_HEADSET_AND_SPEAKER:
                        pr_info("%s: setting output path to "
                                        "headset + speaker\n", __func__);
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_NONE;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       if (!out.on) {
-                               if (pdata->headset_gpio >= 0)
-                                       gpio_direction_output(
-                                               pdata->headset_gpio, 0);
-                                       gpio_direction_output(
-                                               pdata->speaker_gpio, 0);
+                       if (out.on)
+                               tegra_setup_audio_out_headset_and_speaker_on();
+                       else
+                               tegra_setup_audio_output_off();
+
+                       current_output = out;
+                       break;
+               case CPCAP_AUDIO_OUT_STANDBY:
+                       current_output.on = !out.on;
+                       if (out.on) {
+                               pr_info("%s: standby mode\n", __func__);
+                               tegra_setup_audio_output_off();
+                               break;
+                       }
+
+                       switch (current_output.id) {
+                       case CPCAP_AUDIO_OUT_SPEAKER:
+                               pr_info("%s: standby off (speaker)", __func__);
+                               tegra_setup_audio_out_speaker_on();
+                               break;
+                       case CPCAP_AUDIO_OUT_HEADSET:
+                               pr_info("%s: standby off (headset)", __func__);
+                               tegra_setup_audio_out_headset_on();
+                               break;
+                       case CPCAP_AUDIO_OUT_HEADSET_AND_SPEAKER:
+                               pr_info("%s: standby off (speaker + headset)",
+                                       __func__);
+                               tegra_setup_audio_out_headset_and_speaker_on();
                                break;
                        }
-                       pdata->state->stdac_primary_speaker =
-                                       CPCAP_AUDIO_OUT_STEREO_HEADSET;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       gpio_direction_output(pdata->speaker_gpio, 1);
-                       gpio_direction_output(pdata->headset_gpio, 1);
                        break;
                }
-               current_output = out.id;
                break;
        case CPCAP_AUDIO_OUT_GET_OUTPUT:
                if (copy_to_user((void __user *)arg, &current_output,
-                                       sizeof(unsigned int)))
+                                       sizeof(current_output)))
                        rc = -EFAULT;
                break;
        case CPCAP_AUDIO_IN_SET_INPUT:
@@ -152,44 +254,53 @@ static long cpcap_audio_ctl_ioctl(struct file *file, unsigned int cmd,
                        goto done;
                }
 
-               pr_info("%s: muting current input before switch\n", __func__);
-
-               pdata->state->microphone = CPCAP_AUDIO_IN_NONE;
-               pdata->state->codec_mute = CPCAP_AUDIO_CODEC_MUTE;
-               pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_MUTE;
-               pdata->state->codec_mode = CPCAP_AUDIO_CODEC_OFF;
-               pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_OFF;
-               cpcap_audio_set_audio_state(pdata->state);
-
-               if (!in.on)
-                       break;
-
-               pdata->state->codec_mute = CPCAP_AUDIO_CODEC_UNMUTE;
-               pdata->state->stdac_mute = CPCAP_AUDIO_STDAC_UNMUTE;
-               pdata->state->codec_mode = CPCAP_AUDIO_CODEC_ON;
-               pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
-
                switch (in.id) {
                case CPCAP_AUDIO_IN_MIC1:
-                       pr_info("%s: setting input path to on-board mic\n",
+                       if (in.on) {
+                               pr_info("%s: setting input path to on-board mic\n",
                                        __func__);
-                       pdata->state->microphone = CPCAP_AUDIO_IN_HANDSET;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       cpcap_audio_register_dump(pdata->state);
+                               tegra_setup_audio_in_handset_on();
+                       } else {
+                               pr_info("%s: mute on-board mic\n", __func__);
+                               tegra_setup_audio_in_mute();
+                       }
+
+                       current_input = in;
                        break;
                case CPCAP_AUDIO_IN_MIC2:
-                       pr_info("%s: setting input path to headset mic\n",
+                       if (in.on) {
+                               pr_info("%s: setting input path to headset mic\n",
                                        __func__);
-                       pdata->state->microphone = CPCAP_AUDIO_IN_HEADSET;
-                       cpcap_audio_set_audio_state(pdata->state);
-                       cpcap_audio_register_dump(pdata->state);
+                               tegra_setup_audio_in_headset_on();
+                       } else {
+                               pr_info("%s: mute headset mic\n", __func__);
+                               tegra_setup_audio_in_mute();
+                       }
+
+                       current_input = in;
+                       break;
+               case CPCAP_AUDIO_IN_STANDBY:
+                       current_input.on = !in.on;
+                       if (in.on) {
+                               pr_info("%s: microphone in standby mode\n",
+                                       __func__);
+                               tegra_setup_audio_in_mute();
+                               break;
+                       }
+                       switch (current_input.id) {
+                       case CPCAP_AUDIO_IN_MIC1:
+                               tegra_setup_audio_in_headset_on();
+                               break;
+                       case CPCAP_AUDIO_IN_MIC2:
+                               tegra_setup_audio_in_handset_on();
+                               break;
+                       }
                        break;
                }
-               current_input = arg;
                break;
        case CPCAP_AUDIO_IN_GET_INPUT:
                if (copy_to_user((void __user *)arg, &current_input,
-                                       sizeof(unsigned int)))
+                                       sizeof(current_input)))
                        rc = -EFAULT;
                break;
        case CPCAP_AUDIO_OUT_SET_VOLUME:
@@ -280,13 +391,6 @@ static int cpcap_audio_probe(struct platform_device *pdev)
        pdata->state->cpcap = cpcap;
        if (cpcap_audio_init(pdata->state, pdata->regulator))
                goto fail3;
-       cpcap_audio_register_dump(pdata->state);
-
-       pdata->state->output_gain = 10;
-       pdata->state->input_gain = 31;
-       pdata->state->stdac_mode = CPCAP_AUDIO_STDAC_ON;
-       cpcap_audio_set_audio_state(pdata->state);
-       cpcap_audio_register_dump(pdata->state);
 
        rc = misc_register(&cpcap_audio_ctl);
        if (rc < 0) {
index 3d3766e03858e2bd466ccb4a16d20eb0246ebd2a..573c3ce376a8755fd7ba1dda6c692a7fe4cab646 100644 (file)
@@ -26,7 +26,8 @@
 #define CPCAP_AUDIO_OUT_SPEAKER                        0
 #define CPCAP_AUDIO_OUT_HEADSET                        1
 #define CPCAP_AUDIO_OUT_HEADSET_AND_SPEAKER    2
-#define CPCAP_AUDIO_OUT_MAX                    2
+#define CPCAP_AUDIO_OUT_STANDBY                        3
+#define CPCAP_AUDIO_OUT_MAX                    3
 
 struct cpcap_audio_stream {
        unsigned id; /* e.g., CPCAP_AUDIO_OUT_SPEAKER or CPCAP_AUDIO_IN_MIC1 */
@@ -42,13 +43,14 @@ struct cpcap_audio_stream {
 #define CPCAP_AUDIO_OUT_SET_VOLUME _IOW(CPCAP_AUDIO_MAGIC, 1, unsigned int)
 
 #define CPCAP_AUDIO_OUT_GET_OUTPUT \
-                       _IOR(CPCAP_AUDIO_MAGIC, 2, unsigned int *)
+                       _IOR(CPCAP_AUDIO_MAGIC, 2, struct cpcap_audio_stream *)
 #define CPCAP_AUDIO_OUT_GET_VOLUME \
                        _IOR(CPCAP_AUDIO_MAGIC, 3, unsigned int *)
 
 #define CPCAP_AUDIO_IN_MIC1            0
 #define CPCAP_AUDIO_IN_MIC2            1
-#define CPCAP_AUDIO_IN_MAX             1
+#define CPCAP_AUDIO_IN_STANDBY         2
+#define CPCAP_AUDIO_IN_MAX             2
 
 #define CPCAP_AUDIO_IN_SET_INPUT   _IOW(CPCAP_AUDIO_MAGIC, 4, \
                        const struct cpcap_audio_stream *)