Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tm6000-stds.c
Go to the documentation of this file.
1 /*
2  * tm6000-stds.c - driver for TM5600/TM6000/TM6010 USB video capture devices
3  *
4  * Copyright (C) 2007 Mauro Carvalho Chehab <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation version 2
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include "tm6000.h"
23 #include "tm6000-regs.h"
24 
25 static unsigned int tm6010_a_mode;
26 module_param(tm6010_a_mode, int, 0644);
27 MODULE_PARM_DESC(tm6010_a_mode, "set tm6010 sif audio mode");
28 
30  unsigned char req;
31  unsigned char reg;
32  unsigned char value;
33 };
34 
35 
39 };
40 
41 static struct tm6000_reg_settings composite_pal_m[] = {
42  { TM6010_REQ07_R3F_RESET, 0x01 },
65  { TM6010_REQ07_R3F_RESET, 0x00 },
66  { 0, 0, 0 }
67 };
68 
69 static struct tm6000_reg_settings composite_pal_nc[] = {
70  { TM6010_REQ07_R3F_RESET, 0x01 },
93  { TM6010_REQ07_R3F_RESET, 0x00 },
94  { 0, 0, 0 }
95 };
96 
97 static struct tm6000_reg_settings composite_pal[] = {
98  { TM6010_REQ07_R3F_RESET, 0x01 },
121  { TM6010_REQ07_R3F_RESET, 0x00 },
122  { 0, 0, 0 }
123 };
124 
125 static struct tm6000_reg_settings composite_secam[] = {
126  { TM6010_REQ07_R3F_RESET, 0x01 },
148  { TM6010_REQ07_R3F_RESET, 0x00 },
149  { 0, 0, 0 }
150 };
151 
152 static struct tm6000_reg_settings composite_ntsc[] = {
153  { TM6010_REQ07_R3F_RESET, 0x01 },
176  { TM6010_REQ07_R3F_RESET, 0x00 },
177  { 0, 0, 0 }
178 };
179 
180 static struct tm6000_std_settings composite_stds[] = {
181  { .id = V4L2_STD_PAL_M, .common = composite_pal_m, },
182  { .id = V4L2_STD_PAL_Nc, .common = composite_pal_nc, },
183  { .id = V4L2_STD_PAL, .common = composite_pal, },
184  { .id = V4L2_STD_SECAM, .common = composite_secam, },
185  { .id = V4L2_STD_NTSC, .common = composite_ntsc, },
186 };
187 
188 static struct tm6000_reg_settings svideo_pal_m[] = {
189  { TM6010_REQ07_R3F_RESET, 0x01 },
212  { TM6010_REQ07_R3F_RESET, 0x00 },
213  { 0, 0, 0 }
214 };
215 
216 static struct tm6000_reg_settings svideo_pal_nc[] = {
217  { TM6010_REQ07_R3F_RESET, 0x01 },
240  { TM6010_REQ07_R3F_RESET, 0x00 },
241  { 0, 0, 0 }
242 };
243 
244 static struct tm6000_reg_settings svideo_pal[] = {
245  { TM6010_REQ07_R3F_RESET, 0x01 },
268  { TM6010_REQ07_R3F_RESET, 0x00 },
269  { 0, 0, 0 }
270 };
271 
272 static struct tm6000_reg_settings svideo_secam[] = {
273  { TM6010_REQ07_R3F_RESET, 0x01 },
295  { TM6010_REQ07_R3F_RESET, 0x00 },
296  { 0, 0, 0 }
297 };
298 
299 static struct tm6000_reg_settings svideo_ntsc[] = {
300  { TM6010_REQ07_R3F_RESET, 0x01 },
324  { TM6010_REQ07_R3F_RESET, 0x00 },
325  { 0, 0, 0 }
326 };
327 
328 static struct tm6000_std_settings svideo_stds[] = {
329  { .id = V4L2_STD_PAL_M, .common = svideo_pal_m, },
330  { .id = V4L2_STD_PAL_Nc, .common = svideo_pal_nc, },
331  { .id = V4L2_STD_PAL, .common = svideo_pal, },
332  { .id = V4L2_STD_SECAM, .common = svideo_secam, },
333  { .id = V4L2_STD_NTSC, .common = svideo_ntsc, },
334 };
335 
336 static int tm6000_set_audio_std(struct tm6000_core *dev)
337 {
338  uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
339  uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
340  uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
341 
342  if (dev->radio) {
348  /* set mono or stereo */
349  if (dev->amode == V4L2_TUNER_MODE_MONO)
351  else if (dev->amode == V4L2_TUNER_MODE_STEREO)
360  return 0;
361  }
362 
363  /*
364  * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one
365  * audio standard for each V4L2_STD type.
366  */
367  if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) {
368  areg_05 |= 0x04;
369  } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) {
370  areg_05 |= 0x43;
371  } else if (dev->norm & V4L2_STD_MN) {
372  areg_05 |= 0x22;
373  } else switch (tm6010_a_mode) {
374  /* auto */
375  case 0:
376  if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L)
377  areg_05 |= 0x00;
378  else /* Other PAL/SECAM standards */
379  areg_05 |= 0x10;
380  break;
381  /* A2 */
382  case 1:
383  if (dev->norm & V4L2_STD_DK)
384  areg_05 = 0x09;
385  else
386  areg_05 = 0x05;
387  break;
388  /* NICAM */
389  case 2:
390  if (dev->norm & V4L2_STD_DK) {
391  areg_05 = 0x06;
392  } else if (dev->norm & V4L2_STD_PAL_I) {
393  areg_05 = 0x08;
394  } else if (dev->norm & V4L2_STD_SECAM_L) {
395  areg_05 = 0x0a;
396  areg_02 = 0x02;
397  } else {
398  areg_05 = 0x07;
399  }
400  break;
401  /* other */
402  case 3:
403  if (dev->norm & V4L2_STD_DK) {
404  areg_05 = 0x0b;
405  } else {
406  areg_05 = 0x02;
407  }
408  break;
409  }
410 
438  tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00);
439  tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00);
444 
445  return 0;
446 }
447 
449 {
450  /* Currently, those are the only supported resoltions */
451  if (dev->norm & V4L2_STD_525_60)
452  dev->height = 480;
453  else
454  dev->height = 576;
455 
456  dev->width = 720;
457 }
458 
459 static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings *set)
460 {
461  int i, rc;
462 
463  /* Load board's initialization table */
464  for (i = 0; set[i].req; i++) {
465  rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value);
466  if (rc < 0) {
467  printk(KERN_ERR "Error %i while setting "
468  "req %d, reg %d to value %d\n",
469  rc, set[i].req, set[i].reg, set[i].value);
470  return rc;
471  }
472  }
473 
474  return 0;
475 }
476 
478 {
479  struct tm6000_input *input;
480  int i, rc = 0;
481  u8 reg_07_fe = 0x8a;
482  u8 reg_08_f1 = 0xfc;
483  u8 reg_08_e2 = 0xf0;
484  u8 reg_08_e6 = 0x0f;
485 
486  tm6000_get_std_res(dev);
487 
488  if (!dev->radio)
489  input = &dev->vinput[dev->input];
490  else
491  input = &dev->rinput;
492 
493  if (dev->dev_type == TM6010) {
494  switch (input->vmux) {
495  case TM6000_VMUX_VIDEO_A:
501  reg_07_fe |= 0x01;
502  break;
503  case TM6000_VMUX_VIDEO_B:
509  reg_07_fe |= 0x01;
510  break;
514  reg_08_e6 = 0x00;
519  break;
520  default:
521  break;
522  }
523  switch (input->amux) {
524  case TM6000_AMUX_ADC1:
526  0x00, 0x0f);
527  /* Mux overflow workaround */
529  0x10, 0xf0);
530  break;
531  case TM6000_AMUX_ADC2:
533  0x08, 0x0f);
534  /* Mux overflow workaround */
536  0x10, 0xf0);
537  break;
538  case TM6000_AMUX_SIF1:
539  reg_08_e2 |= 0x02;
540  reg_08_e6 = 0x08;
541  reg_07_fe |= 0x40;
542  reg_08_f1 |= 0x02;
545  0x02, 0x0f);
546  /* Mux overflow workaround */
548  0x30, 0xf0);
549  break;
550  case TM6000_AMUX_SIF2:
551  reg_08_e2 |= 0x02;
552  reg_08_e6 = 0x08;
553  reg_07_fe |= 0x40;
554  reg_08_f1 |= 0x02;
557  0x02, 0x0f);
558  /* Mux overflow workaround */
560  0x30, 0xf0);
561  break;
562  default:
563  break;
564  }
569  } else {
570  switch (input->vmux) {
571  case TM6000_VMUX_VIDEO_A:
575  tm6000_set_reg(dev,
576  REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
577  break;
578  case TM6000_VMUX_VIDEO_B:
582  tm6000_set_reg(dev,
583  REQ_03_SET_GET_MCU_PIN, input->v_gpio, 0);
584  break;
589  tm6000_set_reg(dev,
590  REQ_03_SET_GET_MCU_PIN, input->v_gpio, 1);
591  break;
592  default:
593  break;
594  }
595  switch (input->amux) {
596  case TM6000_AMUX_ADC1:
598  TM6000_REQ07_REB_VADC_AADC_MODE, 0x00, 0x0f);
599  break;
600  case TM6000_AMUX_ADC2:
602  TM6000_REQ07_REB_VADC_AADC_MODE, 0x04, 0x0f);
603  break;
604  default:
605  break;
606  }
607  }
608  if (input->type == TM6000_INPUT_SVIDEO) {
609  for (i = 0; i < ARRAY_SIZE(svideo_stds); i++) {
610  if (dev->norm & svideo_stds[i].id) {
611  rc = tm6000_load_std(dev, svideo_stds[i].common);
612  goto ret;
613  }
614  }
615  return -EINVAL;
616  } else {
617  for (i = 0; i < ARRAY_SIZE(composite_stds); i++) {
618  if (dev->norm & composite_stds[i].id) {
619  rc = tm6000_load_std(dev, composite_stds[i].common);
620  goto ret;
621  }
622  }
623  return -EINVAL;
624  }
625 
626 ret:
627  if (rc < 0)
628  return rc;
629 
630  if ((dev->dev_type == TM6010) &&
631  ((input->amux == TM6000_AMUX_SIF1) ||
632  (input->amux == TM6000_AMUX_SIF2)))
633  tm6000_set_audio_std(dev);
634 
635  msleep(40);
636 
637  return 0;
638 }