[ARM] cpcap-audio: enable low-power standby mode

-- 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>
This commit is contained in:
James Wylder
2010-09-13 22:19:01 -05:00
committed by Colin Cross
parent a2a2b6311f
commit b031542289
3 changed files with 193 additions and 87 deletions

View 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);

View File

@@ -35,8 +35,12 @@
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) {

View 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 *)