📄 saa7127.c
字号:
/* * saa7127 - Philips SAA7127/SAA7129 video encoder driver * * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl> * * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter * * Copyright (C) 2000-2001 Gillem <htoa@gmx.net> * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de> * * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo * * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org> * * This driver is designed for the Hauppauge 250/350 Linux driver * from the ivtv Project * * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com> * * Dual output support: * Copyright (C) 2004 Eric Varsanyi * * NTSC Tuning and 7.5 IRE Setup * Copyright (C) 2004 Chris Kennedy <c@groovy.org> * * VBI additions & cleanup: * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl> * * Note: the saa7126 is identical to the saa7127, and the saa7128 is * identical to the saa7129, except that the saa7126 and saa7128 have * macrovision anti-taping support. This driver will almost certainly * work find for those chips, except of course for the missing anti-taping * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */#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>static int debug = 0;static int test_image = 0;MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");MODULE_LICENSE("GPL");module_param(debug, int, 0644);module_param(test_image, int, 0644);MODULE_PARM_DESC(debug, "debug level (0-2)");MODULE_PARM_DESC(test_image, "test_image (0-1)");#define saa7127_dbg(fmt, arg...) \ do { \ if (debug >= 1) \ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ i2c_adapter_id(client->adapter), client->addr , ## arg); \ } while (0)/* High volume debug. Use with care. */#define saa7127_dbg_highvol(fmt, arg...) \ do { \ if (debug == 2) \ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ i2c_adapter_id(client->adapter), client->addr , ## arg); \ } while (0)#define saa7127_err(fmt, arg...) do { \ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)#define saa7127_info(fmt, arg...) do { \ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };I2C_CLIENT_INSMOD;/* * SAA7127 registers */#define SAA7127_REG_STATUS 0x00#define SAA7127_REG_WIDESCREEN_CONFIG 0x26#define SAA7127_REG_WIDESCREEN_ENABLE 0x27#define SAA7127_REG_BURST_START 0x28#define SAA7127_REG_BURST_END 0x29#define SAA7127_REG_COPYGEN_0 0x2a#define SAA7127_REG_COPYGEN_1 0x2b#define SAA7127_REG_COPYGEN_2 0x2c#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a#define SAA7129_REG_FADE_KEY_COL2 0x4f#define SAA7127_REG_CHROMA_PHASE 0x5a#define SAA7127_REG_GAINU 0x5b#define SAA7127_REG_GAINV 0x5c#define SAA7127_REG_BLACK_LEVEL 0x5d#define SAA7127_REG_BLANKING_LEVEL 0x5e#define SAA7127_REG_VBI_BLANKING 0x5f#define SAA7127_REG_DAC_CONTROL 0x61#define SAA7127_REG_BURST_AMP 0x62#define SAA7127_REG_SUBC3 0x63#define SAA7127_REG_SUBC2 0x64#define SAA7127_REG_SUBC1 0x65#define SAA7127_REG_SUBC0 0x66#define SAA7127_REG_LINE_21_ODD_0 0x67#define SAA7127_REG_LINE_21_ODD_1 0x68#define SAA7127_REG_LINE_21_EVEN_0 0x69#define SAA7127_REG_LINE_21_EVEN_1 0x6a#define SAA7127_REG_RCV_PORT_CONTROL 0x6b#define SAA7127_REG_VTRIG 0x6c#define SAA7127_REG_HTRIG_HI 0x6d#define SAA7127_REG_MULTI 0x6e#define SAA7127_REG_CLOSED_CAPTION 0x6f#define SAA7127_REG_RCV2_OUTPUT_START 0x70#define SAA7127_REG_RCV2_OUTPUT_END 0x71#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72#define SAA7127_REG_TTX_REQUEST_H_START 0x73#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79#define SAA7127_REG_FIRST_ACTIVE 0x7a#define SAA7127_REG_LAST_ACTIVE 0x7b#define SAA7127_REG_MSB_VERTICAL 0x7c#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f/* ********************************************************************** * * Arrays with configuration parameters for the SAA7127 * ********************************************************************** */struct i2c_reg_value { unsigned char reg; unsigned char value;};static const struct i2c_reg_value saa7129_init_config_extra[] = { { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, { SAA7127_REG_VTRIG, 0xfa },};static const struct i2c_reg_value saa7127_init_config_common[] = { { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, { SAA7127_REG_COPYGEN_0, 0x77 }, { SAA7127_REG_COPYGEN_1, 0x41 }, { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e }, { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ { SAA7127_REG_LINE_21_ODD_0, 0x77 }, { SAA7127_REG_LINE_21_ODD_1, 0x41 }, { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, { SAA7127_REG_VTRIG, 0xf9 }, { SAA7127_REG_HTRIG_HI, 0x00 }, { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, { SAA7127_REG_FIRST_ACTIVE, 0x1a }, { SAA7127_REG_LAST_ACTIVE, 0x01 }, { SAA7127_REG_MSB_VERTICAL, 0xc0 }, { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, { 0, 0 }};#define SAA7127_60HZ_DAC_CONTROL 0x15static const struct i2c_reg_value saa7127_init_config_60hz[] = { { SAA7127_REG_BURST_START, 0x19 }, /* BURST_END is also used as a chip ID in saa7127_detect_client */ { SAA7127_REG_BURST_END, 0x1d }, { SAA7127_REG_CHROMA_PHASE, 0xa3 }, { SAA7127_REG_GAINU, 0x98 }, { SAA7127_REG_GAINV, 0xd3 }, { SAA7127_REG_BLACK_LEVEL, 0x39 }, { SAA7127_REG_BLANKING_LEVEL, 0x2e }, { SAA7127_REG_VBI_BLANKING, 0x2e }, { SAA7127_REG_DAC_CONTROL, 0x15 }, { SAA7127_REG_BURST_AMP, 0x4d }, { SAA7127_REG_SUBC3, 0x1f }, { SAA7127_REG_SUBC2, 0x7c }, { SAA7127_REG_SUBC1, 0xf0 }, { SAA7127_REG_SUBC0, 0x21 }, { SAA7127_REG_MULTI, 0x90 }, { SAA7127_REG_CLOSED_CAPTION, 0x11 }, { 0, 0 }};#define SAA7127_50HZ_DAC_CONTROL 0x02static struct i2c_reg_value saa7127_init_config_50hz[] = { { SAA7127_REG_BURST_START, 0x21 }, /* BURST_END is also used as a chip ID in saa7127_detect_client */ { SAA7127_REG_BURST_END, 0x1d }, { SAA7127_REG_CHROMA_PHASE, 0x3f }, { SAA7127_REG_GAINU, 0x7d }, { SAA7127_REG_GAINV, 0xaf }, { SAA7127_REG_BLACK_LEVEL, 0x33 }, { SAA7127_REG_BLANKING_LEVEL, 0x35 }, { SAA7127_REG_VBI_BLANKING, 0x35 }, { SAA7127_REG_DAC_CONTROL, 0x02 }, { SAA7127_REG_BURST_AMP, 0x2f }, { SAA7127_REG_SUBC3, 0xcb }, { SAA7127_REG_SUBC2, 0x8a }, { SAA7127_REG_SUBC1, 0x09 }, { SAA7127_REG_SUBC0, 0x2a }, { SAA7127_REG_MULTI, 0xa0 }, { SAA7127_REG_CLOSED_CAPTION, 0x00 }, { 0, 0 }};/* Enumeration for the Supported input types */enum saa7127_input_type { SAA7127_INPUT_TYPE_NORMAL, SAA7127_INPUT_TYPE_TEST_IMAGE};/* Enumeration for the Supported Output signal types */enum saa7127_output_type { SAA7127_OUTPUT_TYPE_BOTH, SAA7127_OUTPUT_TYPE_COMPOSITE, SAA7127_OUTPUT_TYPE_SVIDEO, SAA7127_OUTPUT_TYPE_RGB, SAA7127_OUTPUT_TYPE_YUV_C, SAA7127_OUTPUT_TYPE_YUV_V};/* ********************************************************************** * * Encoder Struct, holds the configuration state of the encoder * ********************************************************************** */struct saa7127_state { v4l2_std_id std; enum v4l2_chip_ident ident; enum saa7127_input_type input_type; enum saa7127_output_type output_type; int video_enable; int wss_enable; u16 wss_mode; int cc_enable; u16 cc_data; int xds_enable; u16 xds_data; int vps_enable; u8 vps_data[5]; u8 reg_2d; u8 reg_3a; u8 reg_3a_cb; /* colorbar bit */ u8 reg_61;};static const char * const output_strs[] ={ "S-Video + Composite", "Composite", "S-Video", "RGB", "YUV C", "YUV V"};static const char * const wss_strs[] = { "invalid", "letterbox 14:9 center", "letterbox 14:9 top", "invalid", "letterbox 16:9 top", "invalid", "invalid", "16:9 full format anamorphic" "4:3 full format", "invalid", "invalid", "letterbox 16:9 center", "invalid", "letterbox >16:9 center", "14:9 full format center", "invalid",};/* ----------------------------------------------------------------------- */static int saa7127_read(struct i2c_client *client, u8 reg){ return i2c_smbus_read_byte_data(client, reg);}/* ----------------------------------------------------------------------- */static int saa7127_write(struct i2c_client *client, u8 reg, u8 val){ int i; for (i = 0; i < 3; i++) { if (i2c_smbus_write_byte_data(client, reg, val) == 0) return 0; } saa7127_err("I2C Write Problem\n"); return -1;}/* ----------------------------------------------------------------------- */static int saa7127_write_inittab(struct i2c_client *client, const struct i2c_reg_value *regs){ while (regs->reg != 0) { saa7127_write(client, regs->reg, regs->value); regs++; } return 0;}/* ----------------------------------------------------------------------- */static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data){ struct saa7127_state *state = i2c_get_clientdata(client); int enable = (data->line != 0); if (enable && (data->field != 0 || data->line != 16)) return -EINVAL; if (state->vps_enable != enable) { saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off"); saa7127_write(client, 0x54, enable << 7); state->vps_enable = enable; } if (!enable) return 0; state->vps_data[0] = data->data[4]; state->vps_data[1] = data->data[10]; state->vps_data[2] = data->data[11]; state->vps_data[3] = data->data[12]; state->vps_data[4] = data->data[13]; saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n", state->vps_data[0], state->vps_data[1], state->vps_data[2], state->vps_data[3], state->vps_data[4]); saa7127_write(client, 0x55, state->vps_data[0]); saa7127_write(client, 0x56, state->vps_data[1]); saa7127_write(client, 0x57, state->vps_data[2]); saa7127_write(client, 0x58, state->vps_data[3]); saa7127_write(client, 0x59, state->vps_data[4]); return 0;}/* ----------------------------------------------------------------------- */static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data){ struct saa7127_state *state = i2c_get_clientdata(client); u16 cc = data->data[1] << 8 | data->data[0]; int enable = (data->line != 0); if (enable && (data->field != 0 || data->line != 21)) return -EINVAL; if (state->cc_enable != enable) { saa7127_dbg("Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; } if (!enable) return 0; saa7127_dbg_highvol("CC data: %04x\n", cc); saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8); state->cc_data = cc; return 0;}/* ----------------------------------------------------------------------- */static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data){ struct saa7127_state *state = i2c_get_clientdata(client); u16 xds = data->data[1] << 8 | data->data[0]; int enable = (data->line != 0); if (enable && (data->field != 1 || data->line != 21)) return -EINVAL; if (state->xds_enable != enable) { saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -