aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx25840
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2007-08-05 07:00:36 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:04:55 -0400
commit87410dab1238623e082e9a78a62f1bbeb6c475e3 (patch)
tree521977ac3c7c91b9d97616452047bcddfd066279 /drivers/media/video/cx25840
parent372978055dd564d97ca1b4099c99296eaff1fe19 (diff)
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 <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c53
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c6
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h1
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)
194 194
195static int get_volume(struct i2c_client *client) 195static int get_volume(struct i2c_client *client)
196{ 196{
197 struct cx25840_state *state = i2c_get_clientdata(client);
198 int vol;
199
200 if (state->unmute_volume >= 0)
201 return state->unmute_volume;
202
197 /* Volume runs +18dB to -96dB in 1/2dB steps 203 /* Volume runs +18dB to -96dB in 1/2dB steps
198 * change to fit the msp3400 -114dB to +12dB range */ 204 * change to fit the msp3400 -114dB to +12dB range */
199 205
200 /* check PATH1_VOLUME */ 206 /* check PATH1_VOLUME */
201 int vol = 228 - cx25840_read(client, 0x8d4); 207 vol = 228 - cx25840_read(client, 0x8d4);
202 vol = (vol / 2) + 23; 208 vol = (vol / 2) + 23;
203 return vol << 9; 209 return vol << 9;
204} 210}
205 211
206static void set_volume(struct i2c_client *client, int volume) 212static void set_volume(struct i2c_client *client, int volume)
207{ 213{
208 /* First convert the volume to msp3400 values (0-127) */ 214 struct cx25840_state *state = i2c_get_clientdata(client);
209 int vol = volume >> 9; 215 int vol;
216
217 if (state->unmute_volume >= 0) {
218 state->unmute_volume = volume;
219 return;
220 }
221
222 /* Convert the volume to msp3400 values (0-127) */
223 vol = volume >> 9;
224
210 /* now scale it up to cx25840 values 225 /* now scale it up to cx25840 values
211 * -114dB to -96dB maps to 0 226 * -114dB to -96dB maps to 0
212 * this should be 19, but in my testing that was 4dB too loud */ 227 * 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)
284 299
285static int get_mute(struct i2c_client *client) 300static int get_mute(struct i2c_client *client)
286{ 301{
287 /* check SRC1_MUTE_EN */ 302 struct cx25840_state *state = i2c_get_clientdata(client);
288 return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; 303
304 return state->unmute_volume >= 0;
289} 305}
290 306
291static void set_mute(struct i2c_client *client, int mute) 307static void set_mute(struct i2c_client *client, int mute)
292{ 308{
293 struct cx25840_state *state = i2c_get_clientdata(client); 309 struct cx25840_state *state = i2c_get_clientdata(client);
294 310
295 if (state->aud_input != CX25840_AUDIO_SERIAL) { 311 if (mute && state->unmute_volume == -1) {
296 /* Must turn off microcontroller in order to mute sound. 312 int vol = get_volume(client);
297 * Not sure if this is the best method, but it does work. 313
298 * If the microcontroller is running, then it will undo any 314 set_volume(client, 0);
299 * changes to the mute register. */ 315 state->unmute_volume = vol;
300 if (mute) { 316 }
301 /* disable microcontroller */ 317 else if (!mute && state->unmute_volume != -1) {
302 cx25840_and_or(client, 0x803, ~0x10, 0x00); 318 int vol = state->unmute_volume;
303 cx25840_write(client, 0x8d3, 0x1f); 319
304 } else { 320 state->unmute_volume = -1;
305 /* enable microcontroller */ 321 set_volume(client, vol);
306 cx25840_and_or(client, 0x803, ~0x10, 0x10);
307 }
308 } else {
309 /* SRC1_MUTE_EN */
310 cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
311 } 322 }
312} 323}
313 324
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,
915 state->audclk_freq = 48000; 915 state->audclk_freq = 48000;
916 state->pvr150_workaround = 0; 916 state->pvr150_workaround = 0;
917 state->audmode = V4L2_TUNER_MODE_LANG1; 917 state->audmode = V4L2_TUNER_MODE_LANG1;
918 state->unmute_volume = -1;
918 state->vbi_line_offset = 8; 919 state->vbi_line_offset = 8;
919 state->id = id; 920 state->id = id;
920 state->rev = device_id; 921 state->rev = device_id;
@@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client)
1066 } 1067 }
1067 v4l_info(client, "Detected audio standard: %s\n", p); 1068 v4l_info(client, "Detected audio standard: %s\n", p);
1068 v4l_info(client, "Audio muted: %s\n", 1069 v4l_info(client, "Audio muted: %s\n",
1069 (mute_ctl & 0x2) ? "yes" : "no"); 1070 (state->unmute_volume >= 0) ? "yes" : "no");
1070 v4l_info(client, "Audio microcontroller: %s\n", 1071 v4l_info(client, "Audio microcontroller: %s\n",
1071 (download_ctl & 0x10) ? "running" : "stopped"); 1072 (download_ctl & 0x10) ?
1073 ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
1072 1074
1073 switch (audio_config >> 4) { 1075 switch (audio_config >> 4) {
1074 case 0x00: p = "undefined"; break; 1076 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 {
42 enum cx25840_audio_input aud_input; 42 enum cx25840_audio_input aud_input;
43 u32 audclk_freq; 43 u32 audclk_freq;
44 int audmode; 44 int audmode;
45 int unmute_volume; /* -1 if not muted */
45 int vbi_line_offset; 46 int vbi_line_offset;
46 u32 id; 47 u32 id;
47 u32 rev; 48 u32 rev;