aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/em28xx/em28xx-core.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-11-19 10:01:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-29 14:53:35 -0500
commit35643943be58aef82826e340761e86e0d37870ec (patch)
tree79ecb4cbc21075dcc8a9740021c6acf089564038 /drivers/media/video/em28xx/em28xx-core.c
parent8a5caa6bcb03b72db6c19a11e7b2de7656bd3f26 (diff)
V4L/DVB (9651): em28xx: Improve audio handling
This patch properly implements audio handling on em28xx. Before this patch, it was assumed that every device has an Empia 202 audio chip. However, this is not true. After this patch, specific AC97 chipset setup and configurations can be done. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-core.c')
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c253
1 files changed, 205 insertions, 48 deletions
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 4de1b2d433a4..2f3257e87027 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -224,15 +224,70 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
224} 224}
225 225
226/* 226/*
227 * em28xx_is_ac97_ready()
228 * Checks if ac97 is ready
229 */
230static int em28xx_is_ac97_ready(struct em28xx *dev)
231{
232 int ret, i;
233
234 /* Wait up to 50 ms for AC97 command to complete */
235 for (i = 0; i < 10; i++, msleep(5)) {
236 ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
237 if (ret < 0)
238 return ret;
239
240 if (!(ret & 0x01))
241 return 0;
242 }
243
244 em28xx_warn("AC97 command still being executed: not handled properly!\n");
245 return -EBUSY;
246}
247
248/*
249 * em28xx_read_ac97()
250 * write a 16 bit value to the specified AC97 address (LSB first!)
251 */
252static int em28xx_read_ac97(struct em28xx *dev, u8 reg)
253{
254 int ret;
255 u8 addr = (reg & 0x7f) | 0x80;
256 u16 val;
257
258 ret = em28xx_is_ac97_ready(dev);
259 if (ret < 0)
260 return ret;
261
262 ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
263 if (ret < 0)
264 return ret;
265
266 ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
267 (u8 *)&val, sizeof(val));
268
269 if (ret < 0)
270 return ret;
271 return le16_to_cpu(val);
272}
273
274/*
227 * em28xx_write_ac97() 275 * em28xx_write_ac97()
228 * write a 16 bit value to the specified AC97 address (LSB first!) 276 * write a 16 bit value to the specified AC97 address (LSB first!)
229 */ 277 */
230static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) 278static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
231{ 279{
232 int ret, i; 280 int ret;
233 u8 addr = reg & 0x7f; 281 u8 addr = reg & 0x7f;
282 __le16 value;
283
284 value = cpu_to_le16(val);
285
286 ret = em28xx_is_ac97_ready(dev);
287 if (ret < 0)
288 return ret;
234 289
235 ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2); 290 ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
236 if (ret < 0) 291 if (ret < 0)
237 return ret; 292 return ret;
238 293
@@ -240,25 +295,36 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
240 if (ret < 0) 295 if (ret < 0)
241 return ret; 296 return ret;
242 297
243 /* Wait up to 50 ms for AC97 command to complete */ 298 return 0;
244 for (i = 0; i < 10; i++) { 299}
245 ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
246 if (ret < 0)
247 return ret;
248 300
249 if (!(ret & 0x01)) 301static int set_ac97_em202_input(struct em28xx *dev)
250 return 0; 302{
251 msleep(5); 303 int ret;
304 u16 enable = 0x0808; /* 12 dB attenuation Left/Right */
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;
252 } 314 }
253 em28xx_warn("AC97 command still being executed: not handled properly!\n"); 315
254 return 0; 316 /* Sets em202 AC97 mixer registers */
317 ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video);
318 if (ret < 0)
319 return ret;
320
321 ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line);
322
323 return ret;
255} 324}
256 325
257static int em28xx_set_audio_source(struct em28xx *dev) 326static int em28xx_set_audio_source(struct em28xx *dev)
258{ 327{
259 static char *enable = "\x08\x08";
260 static char *disable = "\x08\x88";
261 char *video = enable, *line = disable;
262 int ret; 328 int ret;
263 u8 input; 329 u8 input;
264 330
@@ -280,18 +346,8 @@ static int em28xx_set_audio_source(struct em28xx *dev)
280 case EM28XX_AMUX_VIDEO: 346 case EM28XX_AMUX_VIDEO:
281 input = EM28XX_AUDIO_SRC_TUNER; 347 input = EM28XX_AUDIO_SRC_TUNER;
282 break; 348 break;
283 case EM28XX_AMUX_LINE_IN: 349 default:
284 input = EM28XX_AUDIO_SRC_LINE; 350 input = EM28XX_AUDIO_SRC_LINE;
285 video = disable;
286 line = enable;
287 break;
288 case EM28XX_AMUX_AC97_VIDEO:
289 input = EM28XX_AUDIO_SRC_LINE;
290 break;
291 case EM28XX_AMUX_AC97_LINE_IN:
292 input = EM28XX_AUDIO_SRC_LINE;
293 video = disable;
294 line = enable;
295 break; 351 break;
296 } 352 }
297 } 353 }
@@ -301,33 +357,36 @@ static int em28xx_set_audio_source(struct em28xx *dev)
301 return ret; 357 return ret;
302 msleep(5); 358 msleep(5);
303 359
304 /* Sets AC97 mixer registers 360 switch (dev->audio_mode.ac97) {
305 This is seems to be needed, even for non-ac97 configs 361 case EM28XX_NO_AC97:
306 */ 362 break;
307 ret = em28xx_write_ac97(dev, AC97_VIDEO_VOL, video); 363 case EM28XX_AC97_OTHER:
308 if (ret < 0) 364 /* We don't know how to handle this chip.
309 return ret; 365 Let's hope it is close enough to em202 to work
310 366 */
311 ret = em28xx_write_ac97(dev, AC97_LINEIN_VOL, line); 367 case EM28XX_AC97_EM202:
368 ret = set_ac97_em202_input(dev);
369 break;
370 }
312 371
313 return ret; 372 return 0;
314} 373}
315 374
316int em28xx_audio_analog_set(struct em28xx *dev) 375int em28xx_audio_analog_set(struct em28xx *dev)
317{ 376{
318 int ret; 377 int ret;
319 char s[2] = { 0x00, 0x00 };
320 u8 xclk = 0x07; 378 u8 xclk = 0x07;
321 379
322 s[0] |= 0x1f - dev->volume; 380 if (!dev->audio_mode.has_audio)
323 s[1] |= 0x1f - dev->volume; 381 return 0;
324 382
325 /* Mute */ 383 if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
326 s[1] |= 0x80; 384 /* Mute */
327 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); 385 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000);
328 386
329 if (ret < 0) 387 if (ret < 0)
330 return ret; 388 return ret;
389 }
331 390
332 if (dev->has_12mhz_i2s) 391 if (dev->has_12mhz_i2s)
333 xclk |= 0x20; 392 xclk |= 0x20;
@@ -343,15 +402,113 @@ int em28xx_audio_analog_set(struct em28xx *dev)
343 /* Selects the proper audio input */ 402 /* Selects the proper audio input */
344 ret = em28xx_set_audio_source(dev); 403 ret = em28xx_set_audio_source(dev);
345 404
346 /* Unmute device */ 405 /* Sets volume */
347 if (!dev->mute) 406 if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
348 s[1] &= ~0x80; 407 int vol;
349 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, s); 408
409 /* LSB: left channel - both channels with the same level */
410 vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
411
412 /* Mute device, if needed */
413 if (dev->mute)
414 vol |= 0x8000;
415
416 /* Sets volume */
417 ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, vol);
418 }
350 419
351 return ret; 420 return ret;
352} 421}
353EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); 422EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
354 423
424int em28xx_audio_setup(struct em28xx *dev)
425{
426 int vid1, vid2, feat, cfg;
427
428 if (dev->chip_id == CHIP_ID_EM2874) {
429 /* Digital only device - don't load any alsa module */
430 dev->audio_mode.has_audio = 0;
431 dev->has_audio_class = 0;
432 dev->has_alsa_audio = 0;
433 return 0;
434 }
435
436 /* If device doesn't support Usb Audio Class, use vendor class */
437 if (!dev->has_audio_class)
438 dev->has_alsa_audio = 1;
439
440 dev->audio_mode.has_audio = 1;
441
442 /* See how this device is configured */
443 cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
444 if (cfg < 0)
445 cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
446 else
447 em28xx_info("Config register raw data: 0x%02x\n", cfg);
448
449 if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
450 EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
451 em28xx_info("I2S Audio (3 sample rates)\n");
452 dev->audio_mode.i2s_3rates = 1;
453 }
454 if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
455 EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
456 em28xx_info("I2S Audio (5 sample rates)\n");
457 dev->audio_mode.i2s_5rates = 1;
458 }
459
460 if (!(cfg & EM28XX_CHIPCFG_AC97)) {
461 dev->audio_mode.ac97 = EM28XX_NO_AC97;
462 goto init_audio;
463 }
464
465 dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
466
467 vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
468 if (vid1 < 0) {
469 /* Device likely doesn't support AC97 */
470 em28xx_warn("AC97 chip type couldn't be determined\n");
471 goto init_audio;
472 }
473
474 vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
475 if (vid2 < 0)
476 goto init_audio;
477
478 dev->audio_mode.ac97_vendor_id1 = vid1;
479 dev->audio_mode.ac97_vendor_id2 = vid2;
480 em28xx_warn("AC97 vendor ID = %04x:%04x\n", vid1, vid2);
481
482 feat = em28xx_read_ac97(dev, AC97_RESET);
483 if (feat < 0)
484 goto init_audio;
485
486 dev->audio_mode.ac97_feat = feat;
487 em28xx_warn("AC97 features = 0x%04x\n", feat);
488
489 if ((vid1 == 0xffff) && (vid2 == 0xffff) && (feat == 0x6a90))
490 dev->audio_mode.ac97 = EM28XX_AC97_EM202;
491
492init_audio:
493 /* Reports detected AC97 processor */
494 switch (dev->audio_mode.ac97) {
495 case EM28XX_NO_AC97:
496 em28xx_info("No AC97 audio processor\n");
497 break;
498 case EM28XX_AC97_EM202:
499 em28xx_info("Empia 202 AC97 audio processor detected\n");
500 break;
501 case EM28XX_AC97_OTHER:
502 em28xx_warn("Unknown AC97 audio processor detected!\n");
503 break;
504 default:
505 break;
506 }
507
508 return em28xx_audio_analog_set(dev);
509}
510EXPORT_SYMBOL_GPL(em28xx_audio_setup);
511
355int em28xx_colorlevels_set_default(struct em28xx *dev) 512int em28xx_colorlevels_set_default(struct em28xx *dev)
356{ 513{
357 em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ 514 em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */