From 87410dab1238623e082e9a78a62f1bbeb6c475e3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 5 Aug 2007 08:00:36 -0300 Subject: [PATCH] V4L/DVB (5997): cx25840: fix audio mute handling and reporting Audio muting for the tuner input was implemented by stopping the audio microcontroller and restarting it on unmute. However, it appears that this method can actually crash the audio firmware. It's rare and seems to happen with NTSC only. It has been reimplemented by setting to volume to 0. In addition, the reporting of the mute state has been improved as well: it used to be impossible to detect whether the audio was muted by the user or if it was muted due to the microcontroller trying to detect the audio standard. This is now clearly stated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx25840/cx25840-audio.c | 53 +++++++++++++-------- drivers/media/video/cx25840/cx25840-core.c | 6 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f897c1ebd5f3..f93b5160bb4f 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -194,19 +194,34 @@ void cx25840_audio_set_path(struct i2c_client *client) static int get_volume(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) + return state->unmute_volume; + /* Volume runs +18dB to -96dB in 1/2dB steps * change to fit the msp3400 -114dB to +12dB range */ /* check PATH1_VOLUME */ - int vol = 228 - cx25840_read(client, 0x8d4); + vol = 228 - cx25840_read(client, 0x8d4); vol = (vol / 2) + 23; return vol << 9; } static void set_volume(struct i2c_client *client, int volume) { - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; + struct cx25840_state *state = i2c_get_clientdata(client); + int vol; + + if (state->unmute_volume >= 0) { + state->unmute_volume = volume; + return; + } + + /* Convert the volume to msp3400 values (0-127) */ + vol = volume >> 9; + /* now scale it up to cx25840 values * -114dB to -96dB maps to 0 * this should be 19, but in my testing that was 4dB too loud */ @@ -284,30 +299,26 @@ static void set_balance(struct i2c_client *client, int balance) static int get_mute(struct i2c_client *client) { - /* check SRC1_MUTE_EN */ - return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; + struct cx25840_state *state = i2c_get_clientdata(client); + + return state->unmute_volume >= 0; } static void set_mute(struct i2c_client *client, int mute) { struct cx25840_state *state = i2c_get_clientdata(client); - if (state->aud_input != CX25840_AUDIO_SERIAL) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - if (mute) { - /* disable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - cx25840_write(client, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } - } else { - /* SRC1_MUTE_EN */ - cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + if (mute && state->unmute_volume == -1) { + int vol = get_volume(client); + + set_volume(client, 0); + state->unmute_volume = vol; + } + else if (!mute && state->unmute_volume != -1) { + int vol = state->unmute_volume; + + state->unmute_volume = -1; + set_volume(client, vol); } } diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9f99007d389b..65ad7943dd9a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -915,6 +915,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->audclk_freq = 48000; state->pvr150_workaround = 0; state->audmode = V4L2_TUNER_MODE_LANG1; + state->unmute_volume = -1; state->vbi_line_offset = 8; state->id = id; state->rev = device_id; @@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client) } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); + (state->unmute_volume >= 0) ? "yes" : "no"); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { case 0x00: p = "undefined"; break; diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8c1fbd9b87c1..86e2edfc4941 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -42,6 +42,7 @@ struct cx25840_state { enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; + int unmute_volume; /* -1 if not muted */ int vbi_line_offset; u32 id; u32 rev; -- GitLab