📄 saa7115.c
字号:
/* saa711x - Philips SAA711x video decoder driver * This driver can work with saa7111, saa7111a, saa7113, saa7114, * saa7115 and saa7118. * * Based on saa7114 driver by Maxim Yevtyushkin, which is based on * the saa7111 driver by Dave Perks. * * Copyright (C) 1998 Dave Perks <dperks@ibm.net> * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com> * * Slight changes for video timing and attachment output by * Wolfgang Scherr <scherr@net4you.net> * * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003) * by Ronald Bultje <rbultje@ronald.bitfreak.net> * * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> * (2/17/2003) * * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> * * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> * SAA7111, SAA7113 and SAA7118 support * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */#include "saa711x_regs.h"#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/videodev2.h>#include <media/v4l2-common.h>#include <media/v4l2-chip-ident.h>#include <media/v4l2-i2c-drv-legacy.h>#include <media/saa7115.h>#include <asm/div64.h>#include "compat.h"#define VRES_60HZ (480+16)MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " "Hans Verkuil, Mauro Carvalho Chehab");MODULE_LICENSE("GPL");static int debug;module_param(debug, bool, 0644);MODULE_PARM_DESC(debug, "Debug level (0-1)");static unsigned short normal_i2c[] = { 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */ I2C_CLIENT_END };I2C_CLIENT_INSMOD;struct saa711x_state { v4l2_std_id std; int input; int output; int enable; int radio; int bright; int contrast; int hue; int sat; int width; int height; u32 ident; u32 audclk_freq; u32 crystal_freq; u8 ucgc; u8 cgcdiv; u8 apll;};/* ----------------------------------------------------------------------- */static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value){ return i2c_smbus_write_byte_data(client, reg, value);}/* Sanity routine to check if a register is present */static int saa711x_has_reg(const int id, const u8 reg){ if (id == V4L2_IDENT_SAA7111) return reg < 0x20 && reg != 0x01 && reg != 0x0f && (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e; /* common for saa7113/4/5/8 */ if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f || reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) || reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) || reg == 0x82 || (reg >= 0x89 && reg <= 0x8e))) return 0; switch (id) { case V4L2_IDENT_SAA7113: return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) && reg != 0x5d && reg < 0x63; case V4L2_IDENT_SAA7114: return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) && (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 && reg != 0x81 && reg < 0xf0; case V4L2_IDENT_SAA7115: return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe); case V4L2_IDENT_SAA7118: return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) && (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 && (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0; } return 1;}static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs){ struct saa711x_state *state = i2c_get_clientdata(client); unsigned char reg, data; while (*regs != 0x00) { reg = *(regs++); data = *(regs++); /* According with datasheets, reserved regs should be filled with 0 - seems better not to touch on they */ if (saa711x_has_reg(state->ident,reg)) { if (saa711x_write(client, reg, data) < 0) return -1; } else { v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg); } } return 0;}static inline int saa711x_read(struct i2c_client *client, u8 reg){ return i2c_smbus_read_byte_data(client, reg);}/* ----------------------------------------------------------------------- *//* SAA7111 initialization table */static const unsigned char saa7111_init[] = { R_01_INC_DELAY, 0x00, /* reserved */ /*front end */ R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */ R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, * GAFIX=0, GAI1=256, GAI2=256 */ R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */ R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */ /* decoder */ R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz) * pixels after end of last line */ R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to * work with NTSC, too */ R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0, * VTRC=1, HPLL=0, VNOI=0 */ R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0, * VBLB=0, UPTCV=0, APER=1 */ R_0A_LUMA_BRIGHT_CNTL, 0x80, R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */ R_0C_CHROMA_SAT_CNTL, 0x40, R_0D_CHROMA_HUE_CNTL, 0x00, R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, * FCTC=0, CHBW=1 */ R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */ R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, * OEYC=1, OEHV=1, VIPB=0, COLO=0 */ R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */ R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */ R_14_ANAL_ADC_COMPAT_CNTL, 0x00, R_15_VGATE_START_FID_CHG, 0x00, R_16_VGATE_STOP, 0x00, R_17_MISC_VGATE_CONF_AND_MSB, 0x00, 0x00, 0x00};/* SAA7113 init codes */static const unsigned char saa7113_init[] = { R_01_INC_DELAY, 0x08, R_02_INPUT_CNTL_1, 0xc2, R_03_INPUT_CNTL_2, 0x30, R_04_INPUT_CNTL_3, 0x00, R_05_INPUT_CNTL_4, 0x00, R_06_H_SYNC_START, 0x89, R_07_H_SYNC_STOP, 0x0d, R_08_SYNC_CNTL, 0x88, R_09_LUMA_CNTL, 0x01, R_0A_LUMA_BRIGHT_CNTL, 0x80, R_0B_LUMA_CONTRAST_CNTL, 0x47, R_0C_CHROMA_SAT_CNTL, 0x40, R_0D_CHROMA_HUE_CNTL, 0x00, R_0E_CHROMA_CNTL_1, 0x01, R_0F_CHROMA_GAIN_CNTL, 0x2a, R_10_CHROMA_CNTL_2, 0x08, R_11_MODE_DELAY_CNTL, 0x0c, R_12_RT_SIGNAL_CNTL, 0x07, R_13_RT_X_PORT_OUT_CNTL, 0x00, R_14_ANAL_ADC_COMPAT_CNTL, 0x00, R_15_VGATE_START_FID_CHG, 0x00, R_16_VGATE_STOP, 0x00, R_17_MISC_VGATE_CONF_AND_MSB, 0x00, 0x00, 0x00};/* If a value differs from the Hauppauge driver values, then the comment starts with 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the Hauppauge driver sets. *//* SAA7114 and SAA7115 initialization table */static const unsigned char saa7115_init_auto_input[] = { /* Front-End Part */ R_01_INC_DELAY, 0x48, /* white peak control disabled */ R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */ R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */ R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */ /* Decoder Part */ R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */ R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */ R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */ R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */ R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */ R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */ R_0D_CHROMA_HUE_CNTL, 0x00, R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */ R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */ R_11_MODE_DELAY_CNTL, 0x00, R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */ R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */ R_14_ANAL_ADC_COMPAT_CNTL, 0x00, R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */ R_19_RAW_DATA_OFF_CNTL, 0x80, R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */ R_1B_MISC_TVVCRDET, 0x42, /* recommended value */ R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */ R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */ R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */ /* Power Device Control */ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */ 0x00, 0x00};/* Used to reset saa7113, saa7114 and saa7115 */static const unsigned char saa7115_cfg_reset_scaler[] = { R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */ 0x00, 0x00};/* ============== SAA7715 VIDEO templates ============= */static const unsigned char saa7115_cfg_60hz_video[] = { R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ R_15_VGATE_START_FID_CHG, 0x03, R_16_VGATE_STOP, 0x11, R_17_MISC_VGATE_CONF_AND_MSB, 0x9c, R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */ R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */ R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */ /* Task A */ R_90_A_TASK_HANDLING_CNTL, 0x80, R_91_A_X_PORT_FORMATS_AND_CONF, 0x48, R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40, R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84, /* hoffset low (input), 0x0002 is minimum */ R_94_A_HORIZ_INPUT_WINDOW_START, 0x01, R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00, /* hsize low (input), 0x02d0 = 720 */ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, R_98_A_VERT_INPUT_WINDOW_START, 0x05, R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00, R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c, R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00, R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0, R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c, R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* Task B */ R_C0_B_TASK_HANDLING_CNTL, 0x00, R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08, R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00, R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80, /* 0x0002 is minimum */ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02, R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00, /* 0x02d0 = 720 */ R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, /* vwindow start 0x12 = 18 */ R_C8_B_VERT_INPUT_WINDOW_START, 0x12, R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00, /* vwindow length 0xf8 = 248 */ R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1, R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9, /* hwindow 0x02d0 = 720 */ R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02, R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */ R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */ R_F5_PULSGEN_LINE_LENGTH, 0xad, R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, 0x00, 0x00};static const unsigned char saa7115_cfg_50hz_video[] = { R_80_GLOBAL_CNTL_1, 0x00, R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */ R_16_VGATE_STOP, 0x16, R_17_MISC_VGATE_CONF_AND_MSB, 0x99, R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */ R_0E_CHROMA_CNTL_1, 0x07, R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */ /* Task A */ R_90_A_TASK_HANDLING_CNTL, 0x81, R_91_A_X_PORT_FORMATS_AND_CONF, 0x48, R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40, R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84, /* This is weird: the datasheet says that you should use 2 as the minimum value, */ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */ /* hoffset low (input), 0x0002 is minimum */ R_94_A_HORIZ_INPUT_WINDOW_START, 0x00, R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00, /* hsize low (input), 0x02d0 = 720 */ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0, R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02, R_98_A_VERT_INPUT_WINDOW_START, 0x03, R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00, /* vsize 0x12 = 18 */ R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12, R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00, /* hsize 0x05a0 = 1440 */ R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0, R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */ R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */ R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */ /* Task B */ R_C0_B_TASK_HANDLING_CNTL, 0x00, R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08, R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00, R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80, /* This is weird: the datasheet says that you should use 2 as the minimum value, */ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */ /* hoffset low (input), 0x0002 is minimum. See comment above. */ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -