aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-11-20 07:06:09 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-29 14:53:35 -0500
commit5faff78904d9c07f38ac0e227b322e9f58d5447c (patch)
tree431d2e8c8fc7a17396e806f778293629226fc892 /drivers
parent16c7bcadff2222b297d13951dc30e133f56d0154 (diff)
V4L/DVB (9653): em28xx: improve AC97 handling
AC97 devices provide several input and outputs. However, before this patch, em28xx device weren't properly allowing the usage of ac97 possible combinations. Also, several input volumes were left untouched, instead of making sure that the volumes were set on mute state. This patch improves support for ac97 devices by allowing to use any inputs, and making sure that unused inputs are set on mute state. Yet, some work is still needed to select the AC97 output. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c73
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h14
-rw-r--r--drivers/media/video/em28xx/em28xx.h20
3 files changed, 74 insertions, 33 deletions
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index b0a238421f2b..1cf5b443092c 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -298,29 +298,44 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
298 return 0; 298 return 0;
299} 299}
300 300
301static int set_ac97_em202_input(struct em28xx *dev) 301struct em28xx_input_table {
302 enum em28xx_amux amux;
303 u8 reg;
304};
305
306static struct em28xx_input_table inputs[] = {
307 { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL },
308 { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL },
309 { EM28XX_AMUX_PHONE, AC97_PHONE_VOL },
310 { EM28XX_AMUX_MIC, AC97_MIC_VOL },
311 { EM28XX_AMUX_CD, AC97_CD_VOL },
312 { EM28XX_AMUX_AUX, AC97_AUX_VOL },
313 { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL },
314};
315
316static int set_ac97_input(struct em28xx *dev)
302{ 317{
303 int ret; 318 int ret, i;
304 u16 enable = 0x0808; /* 12 dB attenuation Left/Right */ 319 enum em28xx_amux amux = dev->ctl_ainput;
305 u16 disable = 0x8808; /* bit 15 - mute volumme */
306 u16 video, line;
307
308 if (dev->ctl_ainput == EM28XX_AMUX_VIDEO) {
309 video = enable;
310 line = disable;
311 } else {
312 video = disable;
313 line = enable;
314 }
315 320
316 /* Sets em202 AC97 mixer registers */ 321 /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
317 ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); 322 em28xx should point to LINE IN, while AC97 should use VIDEO
318 if (ret < 0) 323 */
319 return ret; 324 if (amux == EM28XX_AMUX_VIDEO2)
325 amux = dev->ctl_ainput;
320 326
321 ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); 327 /* Mute all entres but the one that were selected */
328 for (i = 0; i < ARRAY_SIZE(inputs); i++) {
329 if (amux == inputs[i].amux)
330 ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
331 else
332 ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
322 333
323 return ret; 334 if (ret < 0)
335 em28xx_warn("couldn't setup AC97 register %d\n",
336 inputs[i].reg);
337 }
338 return 0;
324} 339}
325 340
326static int em28xx_set_audio_source(struct em28xx *dev) 341static int em28xx_set_audio_source(struct em28xx *dev)
@@ -329,10 +344,10 @@ static int em28xx_set_audio_source(struct em28xx *dev)
329 u8 input; 344 u8 input;
330 345
331 if (dev->is_em2800) { 346 if (dev->is_em2800) {
332 if (dev->ctl_ainput) 347 if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
333 input = EM2800_AUDIO_SRC_LINE;
334 else
335 input = EM2800_AUDIO_SRC_TUNER; 348 input = EM2800_AUDIO_SRC_TUNER;
349 else
350 input = EM2800_AUDIO_SRC_LINE;
336 351
337 ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); 352 ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
338 if (ret < 0) 353 if (ret < 0)
@@ -360,16 +375,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
360 switch (dev->audio_mode.ac97) { 375 switch (dev->audio_mode.ac97) {
361 case EM28XX_NO_AC97: 376 case EM28XX_NO_AC97:
362 break; 377 break;
363 case EM28XX_AC97_OTHER: 378 default:
364 /* We don't know how to handle this chip. 379 ret = set_ac97_input(dev);
365 Let's hope it is close enough to em202 to work
366 */
367 case EM28XX_AC97_EM202:
368 ret = set_ac97_em202_input(dev);
369 break;
370 } 380 }
371 381
372 return 0; 382 return ret;
373} 383}
374 384
375int em28xx_audio_analog_set(struct em28xx *dev) 385int em28xx_audio_analog_set(struct em28xx *dev)
@@ -380,6 +390,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
380 if (!dev->audio_mode.has_audio) 390 if (!dev->audio_mode.has_audio)
381 return 0; 391 return 0;
382 392
393 /* It is assumed that all devices use master volume for output.
394 It would be possible to use also line output.
395 */
383 if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { 396 if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
384 /* Mute */ 397 /* Mute */
385 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000); 398 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000);
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 12c9132b099e..9727f3828dba 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -130,10 +130,13 @@ enum em28xx_chip_id {
130 130
131/* Standard AC97 registers */ 131/* Standard AC97 registers */
132#define AC97_RESET 0x00 132#define AC97_RESET 0x00
133
134 /* Output volumes */
133#define AC97_MASTER_VOL 0x02 135#define AC97_MASTER_VOL 0x02
134#define AC97_LINE_LEVEL_VOL 0x04 136#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */
135#define AC97_MASTER_MONO_VOL 0x06 137#define AC97_MASTER_MONO_VOL 0x06
136 138
139 /* Input volumes */
137#define AC97_PC_BEEP_VOL 0x0a 140#define AC97_PC_BEEP_VOL 0x0a
138#define AC97_PHONE_VOL 0x0c 141#define AC97_PHONE_VOL 0x0c
139#define AC97_MIC_VOL 0x0e 142#define AC97_MIC_VOL 0x0e
@@ -142,8 +145,12 @@ enum em28xx_chip_id {
142#define AC97_VIDEO_VOL 0x14 145#define AC97_VIDEO_VOL 0x14
143#define AC97_AUX_VOL 0x16 146#define AC97_AUX_VOL 0x16
144#define AC97_PCM_OUT_VOL 0x18 147#define AC97_PCM_OUT_VOL 0x18
148
149 /* capture registers */
145#define AC97_RECORD_SELECT 0x1a 150#define AC97_RECORD_SELECT 0x1a
146#define AC97_RECORD_GAIN 0x1c 151#define AC97_RECORD_GAIN 0x1c
152
153 /* control registers */
147#define AC97_GENERAL_PURPOSE 0x20 154#define AC97_GENERAL_PURPOSE 0x20
148#define AC97_3D_CTRL 0x22 155#define AC97_3D_CTRL 0x22
149#define AC97_AUD_INT_AND_PAG 0x24 156#define AC97_AUD_INT_AND_PAG 0x24
@@ -158,10 +165,15 @@ enum em28xx_chip_id {
158#define AC97_PCM_OUT_SURR_SRATE 0x2e 165#define AC97_PCM_OUT_SURR_SRATE 0x2e
159#define AC97_PCM_OUT_LFE_SRATE 0x30 166#define AC97_PCM_OUT_LFE_SRATE 0x30
160#define AC97_PCM_IN_SRATE 0x32 167#define AC97_PCM_IN_SRATE 0x32
168
169 /* For devices with more than 2 channels, extra output volumes */
161#define AC97_LFE_MASTER_VOL 0x36 170#define AC97_LFE_MASTER_VOL 0x36
162#define AC97_SURR_MASTER_VOL 0x38 171#define AC97_SURR_MASTER_VOL 0x38
172
173 /* Digital SPDIF output control */
163#define AC97_SPDIF_OUT_CTRL 0x3a 174#define AC97_SPDIF_OUT_CTRL 0x3a
164 175
176 /* Vendor ID identifier */
165#define AC97_VENDOR_ID1 0x7c 177#define AC97_VENDOR_ID1 0x7c
166#define AC97_VENDOR_ID2 0x7e 178#define AC97_VENDOR_ID2 0x7e
167 179
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index d965caba63e3..6d04ebf46e7c 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -274,9 +274,25 @@ struct em28xx_audio_mode {
274 unsigned int i2s_5rates:1; 274 unsigned int i2s_5rates:1;
275}; 275};
276 276
277/* em28xx has two audio inputs: tuner and line in.
278 However, on most devices, an auxiliary AC97 codec device is used.
279 The AC97 device may have several different inputs and outputs,
280 depending on their model. So, it is possible to use AC97 mixer to
281 address more than two different entries.
282 */
277enum em28xx_amux { 283enum em28xx_amux {
278 EM28XX_AMUX_VIDEO, 284 /* This is the only entry for em28xx tuner input */
279 EM28XX_AMUX_LINE_IN, 285 EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */
286
287 EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */
288
289 /* Some less-common mixer setups */
290 EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */
291 EM28XX_AMUX_PHONE,
292 EM28XX_AMUX_MIC,
293 EM28XX_AMUX_CD,
294 EM28XX_AMUX_AUX,
295 EM28XX_AMUX_PCM_OUT,
280}; 296};
281 297
282struct em28xx_input { 298struct em28xx_input {