From patchwork Fri Aug 21 22:37:04 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: santiago.nunez@ridgerun.com X-Patchwork-Id: 43275 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n7LMeFQp015430 for ; Fri, 21 Aug 2009 22:40:15 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id n7LMbsN4021521; Fri, 21 Aug 2009 17:37:59 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id n7LMbrKu011015; Fri, 21 Aug 2009 17:37:54 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 7442680627; Fri, 21 Aug 2009 17:37:51 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp52.itg.ti.com (dflp52.itg.ti.com [128.247.22.96]) by linux.omap.com (Postfix) with ESMTP id 95EBD80626 for ; Fri, 21 Aug 2009 17:37:49 -0500 (CDT) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp52.itg.ti.com (8.13.7/8.13.7) with ESMTP id n7LMbnuQ004390 for ; Fri, 21 Aug 2009 17:37:49 -0500 (CDT) Received: from mail192-tx2-R.bigfish.com (mail-tx2.bigfish.com [65.55.88.114]) by medina.ext.ti.com (8.13.7/8.13.7) with ESMTP id n7LMbh1v010126 for ; Fri, 21 Aug 2009 17:37:49 -0500 Received: from mail192-tx2 (localhost.localdomain [127.0.0.1]) by mail192-tx2-R.bigfish.com (Postfix) with ESMTP id D39C1B8038B for ; Fri, 21 Aug 2009 22:37:43 +0000 (UTC) X-SpamScore: 25 X-BigFish: vps25(zz655Na4b1o9b28mc8kzz1202hzzz2fh69ih) X-Spam-TCS-SCL: 8:0 X-FB-SS: 5, X-MS-Exchange-Organization-Antispam-Report: OrigIP: 74.208.67.6; Service: EHS Received: by mail192-tx2 (MessageSwitch) id 1250894224440381_4639; Fri, 21 Aug 2009 22:37:04 +0000 (UCT) Received: from mail.navvo.net (mail.navvo.net [74.208.67.6]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail192-tx2.bigfish.com (Postfix) with ESMTP id D63514F0052; Fri, 21 Aug 2009 22:37:03 +0000 (UTC) Received: from [200.122.155.113] (helo=localhost.localdomain) by mail.navvo.net with esmtpa (Exim 4.63) (envelope-from ) id 1MecjA-0002VW-Lx; Fri, 21 Aug 2009 17:37:02 -0500 From: santiago.nunez@ridgerun.com To: m-karicheri2@ti.com Date: Fri, 21 Aug 2009 16:37:04 -0600 Message-Id: <1250894224-16981-1-git-send-email-santiago.nunez@ridgerun.com> X-Mailer: git-send-email 1.6.0.4 X-SA-Exim-Connect-IP: 200.122.155.113 X-SA-Exim-Mail-From: santiago.nunez@ridgerun.com X-Spam-Checker-Version: SpamAssassin 3.1.7-deb (2006-10-05) on mail.navvo.net X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=ALL_TRUSTED,AWL,BAYES_00, NO_REAL_NAME,UPPERCASE_25_50 autolearn=ham version=3.1.7-deb X-SA-Exim-Version: 4.2.1 (built Tue, 09 Jan 2007 17:23:22 +0000) X-SA-Exim-Scanned: Yes (on mail.navvo.net) Cc: davinci-linux-open-source@linux.davincidsp.com, clark.becker@ridgerun.com, Santiago Nunez-Corrales , todd.fischer@ridgerun.com Subject: [PATCH] Adding TVP7002 support for DM365 via VPFE X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.4 Precedence: list List-Id: davinci-linux-open-source.linux.davincidsp.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com From: Santiago Nunez-Corrales --- arch/arm/mach-davinci/board-dm365-evm.c | 76 +- drivers/media/video/Kconfig | 9 + drivers/media/video/Makefile | 1 + drivers/media/video/davinci/vpfe_capture.c | 2 + drivers/media/video/tvp7002.c | 2309 ++++++++++++++++++++++++++++ drivers/media/video/tvp7002_reg.h | 159 ++ include/linux/videodev2.h | 8 + include/media/davinci/vpfe_capture.h | 3 +- include/media/tvp7002.h | 250 +++ include/media/v4l2-chip-ident.h | 3 + 10 files changed, 2815 insertions(+), 5 deletions(-) create mode 100644 drivers/media/video/tvp7002.c create mode 100644 drivers/media/video/tvp7002_reg.h create mode 100644 include/media/tvp7002.h diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 362ac62..54d7eef 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -43,6 +43,7 @@ #include #include #include +#include static inline int have_imager(void) @@ -53,14 +54,20 @@ static inline int have_imager(void) static inline int have_tvp7002(void) { - /* REVISIT when it's supported, trigger via Kconfig */ +#ifdef CONFIG_VIDEO_TVP7002 + return 1; +#else return 0; +#endif } #define DM365_ASYNC_EMIF_CONTROL_BASE 0x01d10000 #define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 #define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000 +#define DM365_ASYNC_EMIF_DATA_CE1_REG3 0x18 +#define DM365_ASYNC_EMIF_VIDEO_MUX_MASK (0x07070707) +#define DM365_ASYNC_EMIF_TVP7002_SEL (0x01010101) #define DM365_EVM_PHY_MASK (0x2) #define DM365_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */ @@ -109,6 +116,13 @@ static struct tvp514x_platform_data tvp5146_pdata = { .vs_polarity = 1 }; +// According to TI's tvp7002 datasheet +static struct tvp7002_platform_data tvp7002_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1 +}; + /* NOTE: this is geared for the standard config, with a socketed * 2 GByte Micron NAND (MT29F16G08FAA) using 128KB sectors. If you * swap chips, maybe with a different block size, partitioning may @@ -243,6 +257,18 @@ static struct v4l2_input tvp5146_inputs[] = { }, }; +#define TVP7002_STD_ALL (V4L2_STD_525_60 | V4L2_STD_625_50 |\ + V4L2_STD_725_50 | V4L2_STD_825_60) +/* Inputs available at the TVP7002 */ +static struct v4l2_input tvp7002_inputs[] = { + { + .index = 0, + .name = "Component", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP7002_STD_ALL, + }, +}; + /* * this is the route info for connecting each input to decoder * ouput that goes to vpfe. There is a one to one correspondence @@ -259,8 +285,20 @@ static struct vpfe_route tvp5146_routes[] = { }, }; +/* + * this is the route info for connecting each input to decoder + * ouput that goes to vpfe. There is a one to one correspondence + * with tvp7002_inputs + */ +static struct vpfe_route tvp7002_routes[] = { + { + .input = TVP7002_RIN_1, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + }, +}; + static struct vpfe_subdev_info vpfe_sub_devs[] = { -{ + { .module_name = "tvp5146", .grp_id = 0, .num_inputs = ARRAY_SIZE(tvp5146_inputs), @@ -276,6 +314,23 @@ static struct vpfe_subdev_info vpfe_sub_devs[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, + }, + { + .module_name = "tvp7002", + .grp_id = 0, + .num_inputs = ARRAY_SIZE(tvp7002_inputs), + .inputs = tvp7002_inputs, + .routes = tvp7002_routes, + .can_route = 1, + .ccdc_if_params = { + .if_type = VPFE_BT1120, + .hdpol = VPFE_PINPOL_POSITIVE, + .vdpol = VPFE_PINPOL_POSITIVE, + }, + .board_info = { + I2C_BOARD_INFO("tvp7002", 0x5c), + .platform_data = &tvp7002_pdata, + }, } }; @@ -286,6 +341,7 @@ static struct vpfe_config vpfe_cfg = { .ccdc = "DM365 ISIF", .num_clocks = 1, .clocks = {"vpss_master"}, +// .setup_input = dm365evm_setup_video_input, }; static struct davinci_mmc_config dm365evm_mmc_config = { @@ -439,6 +495,16 @@ static int __init cpld_leds_init(void) /* run after subsys_initcall() for LEDs */ fs_initcall(cpld_leds_init); +/* Set the input mux for TVP7002 */ +int tvp7002_set_input_mux(unsigned char channel) +{ + u32 val; + val = __raw_readl(DM365_ASYNC_EMIF_DATA_CE1_REG3); + val &= ~DM365_ASYNC_EMIF_VIDEO_MUX_MASK; + val |= DM365_ASYNC_EMIF_TVP7002_SEL; + __raw_writel(val, DM365_ASYNC_EMIF_DATA_CE1_REG3); + return 0; +} static void __init evm_init_cpld(void) { @@ -519,6 +585,8 @@ fail: mux |= 2; resets &= ~BIT(2); label = "tvp7002 HD"; + // Call the input setter + tvp7002_set_input_mux(0); } else { /* default to tvp5146 */ mux |= 5; @@ -526,8 +594,8 @@ fail: label = "tvp5146 SD"; } } - __raw_writeb(mux, cpld + CPLD_MUX); - __raw_writeb(resets, cpld + CPLD_RESETS); + __raw_writel(mux, cpld + CPLD_MUX); + __raw_writel(resets, cpld + CPLD_RESETS); pr_info("EVM: %s video input\n", label); /* REVISIT export switches: NTSC/PAL (SW5.6), EXTRA1 (SW5.2), etc */ diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d3723a1..a35395e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -383,6 +383,15 @@ config VIDEO_TVP5150 To compile this driver as a module, choose M here: the module will be called tvp5150. +config VIDEO_TVP7002 + tristate "Texas Instruments TVP7002 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Texas Instruments TVP7002 video decoder. + + To compile this driver as a module, choose M here: the + module will be called tvp7002. + config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 00fb23e..9a8090e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o obj-$(CONFIG_VIDEO_VINO) += indycam.o obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o +obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index ff8677c..5f18219 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -142,6 +142,8 @@ static struct ccdc_config *ccdc_cfg; const struct vpfe_standard vpfe_standards[] = { {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, + {V4L2_STD_725_50, 1280, 720, {12, 10}, 0}, + {V4L2_STD_825_60, 1920, 1080, {12, 10}, 1}, }; /* Used when raw Bayer image from ccdc is directly captured to SDRAM */ diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c new file mode 100644 index 0000000..60e401d --- /dev/null +++ b/drivers/media/video/tvp7002.c @@ -0,0 +1,2309 @@ +/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics Digitizer + * with Horizontal PLL registers + * + * Copyright (C) 2009 Santiago Nunez-Corrales (santiago.nunez@ridgerun.com) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "tvp7002_reg.h" + +/* + * Macro for identifying whether we are within a SD video mode. Required + * for identifying if extra registers have to be set up. + */ + +#define STD_INDEX(mode) ( (mode) & ~V4L2_STD_TVP7002_BASE_STD ) +#define IS_SD_MODE(mode) ( (mode) <= STD_INDEX(TVP7002_VIDEOP_1920_1080_50) && (mode) >= STD_INDEX(TVP7002_VIDEOI_720_480_30) ) +#define IS_XGA60_MODE(mode) ( (mode) == STD_INDEX(TVP7002_XGA_1024_768_60) ) + +MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver"); +MODULE_AUTHOR("Santiago Nunez-Corrales (santiago.nunez@ridgerun.com)"); +MODULE_LICENSE("GPL"); + +/*** Debugging information ***/ + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +/*** Data structures ***/ + +/* Register default values (according to datasheet) */ +static const struct i2c_reg_value tvp7002_init_default[] = { + /* 0x00: read only */ + { + TVP7002_HPLL_FDBK_DIV_MSBS, 0x67 + }, + { + TVP7002_HPLL_FDBK_DIV_LSBS, 0x20 + }, + { + TVP7002_HPLL_CRTL, 0xa8 + }, + { + TVP7002_HPLL_PHASE_SEL, 0x80 + }, + { + TVP7002_CLAMP_START, 0x32 + }, + { + TVP7002_CLAMP_W, 0x20 + }, + { + TVP7002_HSYNC_OUT_W, 0x20 + }, + { + TVP7002_B_FINE_GAIN, 0x00 + }, + { + TVP7002_G_FINE_GAIN, 0x00 + }, + { + TVP7002_R_FINE_GAIN, 0x00 + }, + { + TVP7002_B_FINE_OFF_MSBS, 0x80 + }, + { + TVP7002_G_FINE_OFF_MSBS, 0x80 + }, + { + TVP7002_R_FINE_OFF_MSBS, 0x80 + }, + { + TVP7002_SYNC_CTL_1, 0x5b + }, + { + TVP7002_HPLL_AND_CLAMP_CTL, 0x2e + }, + { + TVP7002_SYNC_ON_G_THRS, 0x5d + }, + { + TVP7002_SYNC_SEPARATOR_THRS, 0x20 + }, + { + TVP7002_HPLL_PRE_COAST, 0x00 + }, + { + TVP7002_HPLL_POST_COAST, 0x00 + }, + /* 0x14: read only */ + { + TVP7002_OUT_FORMATTER, 0x00 + }, + { + TVP7002_MISC_CTL_1, 0x11 + }, + { + TVP7002_MISC_CTL_2, 0x03 + }, + { + TVP7002_MISC_CTL_3, 0x00 + }, + { + TVP7002_IN_MUX_SEL_1, 0x00 + }, + { + TVP7002_IN_MUX_SEL_2, 0xc2 + }, + { + TVP7002_B_AND_G_COARSE_GAIN, 0x77 + }, + { + TVP7002_R_COARSE_GAIN, 0x07 + }, + { + TVP7002_COARSE_CLAMP_CTL, 0x00 + }, + { + TVP7002_FINE_OFF_LSBS, 0x00 + }, + { + TVP7002_B_COARSE_OFF, 0x10 + }, + { + TVP7002_G_COARSE_OFF, 0x10 + }, + { + TVP7002_R_COARSE_OFF, 0x10 + }, + { + TVP7002_HSOUT_OUT_START, 0x0d + }, + { + TVP7002_MISC_CTL_4, 0x0d + }, + /* 0x23: read only */ + /* 0x24: read only */ + /* 0x25: read only */ + { + TVP7002_AUTO_LVL_CTL_ENABLE, 0x80 + }, + /* 0x27: read only */ + { + TVP7002_AUTO_LVL_CTL_FILTER, 0x53 + }, + { /* Reserved */ + 0x29, 0x08 + }, + { + TVP7002_FINE_CLAMP_CTL, 0x07 + }, + { + TVP7002_PWR_CTL, 0x00 + }, + { + TVP7002_ADC_SETUP, 0x50 + }, + { + TVP7002_COARSE_CLAMP_CTL, 0x00 + }, + { + TVP7002_SOG_CLAMP, 0x80 + }, + { + TVP7002_RGB_COARSE_CLAMP_CTL, 0x8c + }, + { + TVP7002_SOG_COARSE_CLAMP_CTL, 0x04 + }, + { + TVP7002_ALC_PLACEMENT, 0x5a + }, + { /* Reserved */ + 0x32, 0x18 + }, + { /* Reserved */ + 0x33, 0x60 + }, + { + TVP7002_MVIS_STRIPPER_W, 0x03 + }, + { + TVP7002_VSYNC_ALGN, 0x10 + }, + { + TVP7002_SYNC_BYPASS, 0x00 + }, + /* 0x37: read only */ + /* 0x38: read only */ + /* 0x39: read only */ + /* 0x3a: read only */ + /* 0x3b: read only */ + /* 0x3c: read only */ + { + TVP7002_L_LENGTH_TOL, 0x03 + }, + { /* Reserved */ + 0x3e, 0x04 + }, + { + TVP7002_VIDEO_BWTH_CTL, 0x00 + }, + { + TVP7002_AVID_START_PIXEL_LSBS, 0x01 + }, + { + TVP7002_AVID_START_PIXEL_MSBS, 0x2c + }, + { + TVP7002_AVID_STOP_PIXEL_LSBS, 0x06 + }, + { + TVP7002_AVID_STOP_PIXEL_MSBS, 0x2c + }, + { + TVP7002_VBLK_F_0_START_L_OFF, 0x05 + }, + { + TVP7002_VBLK_F_1_START_L_OFF, 0x05 + }, + { + TVP7002_VBLK_F_0_DURATION, 0x1e + }, + { + TVP7002_VBLK_F_1_DURATION, 0x1e + }, + { + TVP7002_FBIT_F_0_START_L_OFF, 0x00 + }, + { + TVP7002_FBIT_F_1_START_L_OFF, 0x00 + }, + { + TVP7002_YUV_Y_G_COEF_LSBS, 0xe3 + }, + { + TVP7002_YUV_Y_G_COEF_MSBS, 0x16 + }, + { + TVP7002_YUV_Y_B_COEF_LSBS, 0x4f + }, + { + TVP7002_YUV_Y_B_COEF_MSBS, 0x02 + }, + { + TVP7002_YUV_Y_R_COEF_LSBS, 0xce + }, + { + TVP7002_YUV_Y_R_COEF_MSBS, 0x06 + }, + { + TVP7002_YUV_U_G_COEF_LSBS, 0xab + }, + { + TVP7002_YUV_U_G_COEF_MSBS, 0xf3 + }, + { + TVP7002_YUV_U_B_COEF_LSBS, 0x00 + }, + { + TVP7002_YUV_U_B_COEF_MSBS, 0x10 + }, + { + TVP7002_YUV_U_R_COEF_LSBS, 0x55 + }, + { + TVP7002_YUV_U_R_COEF_MSBS, 0xfc + }, + { + TVP7002_YUV_V_G_COEF_LSBS, 0x78 + }, + { + TVP7002_YUV_V_G_COEF_MSBS, 0xf1 + }, + { + TVP7002_YUV_V_B_COEF_LSBS, 0x88 + }, + { + TVP7002_YUV_V_B_COEF_MSBS, 0xfe + }, + { + TVP7002_YUV_V_R_COEF_LSBS, 0x00 + }, + { + TVP7002_YUV_V_R_COEF_MSBS, 0x10 + }, + { /* End of registers */ + 0x5c, 0x00 + } +}; + +/* Available resolutions */ +static struct tvp7002_resol tvp7002_resolutions[] = { + { + .id = TVP7002_VGA_640_480_60, + .hres = 640, + .vres = 480, + .frate = 60, + .lrate = 31, + .prate = 25, + .reg01 = 0x32, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_VGA_640_480_73, + .hres = 640, + .vres = 480, + .frate = 73, + .lrate = 38, + .prate = 32, + .reg01 = 0x34, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_VGA_640_480_75, + .hres = 640, + .vres = 480, + .frate = 75, + .lrate = 38, + .prate = 32, + .reg01 = 0x34, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_VGA_640_480_85, + .hres = 640, + .vres = 480, + .frate = 85, + .lrate = 43, + .prate = 36, + .reg01 = 0x34, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SVGA_800_600_56, + .hres = 800, + .vres = 600, + .frate = 56, + .lrate = 35, + .prate = 36, + .reg01 = 0x40, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SVGA_800_600_60, + .hres = 800, + .vres = 600, + .frate = 60, + .lrate = 38, + .prate = 40, + .reg01 = 0x42, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SVGA_800_600_72, + .hres = 800, + .vres = 600, + .frate = 72, + .lrate = 48, + .prate = 50, + .reg01 = 0x41, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SVGA_800_600_75, + .hres = 800, + .vres = 600, + .frate = 75, + .lrate = 47, + .prate = 50, + .reg01 = 0x42, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SVGA_800_600_85, + .hres = 800, + .vres = 600, + .frate = 85, + .lrate = 54, + .prate = 56, + .reg01 = 0x41, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_XGA_1024_768_60, + .hres = 1025, + .vres = 768, + .frate = 60, + .lrate = 48, + .prate = 65, + .reg01 = 0x54, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_XGA_1024_768_70, + .hres = 1025, + .vres = 768, + .frate = 70, + .lrate = 56, + .prate = 75, + .reg01 = 0x53, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x28, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_XGA_1024_768_75, + .hres = 1025, + .vres = 768, + .frate = 75, + .lrate = 60, + .prate = 79, + .reg01 = 0x52, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x28, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_XGA_1024_768_85, + .hres = 1025, + .vres = 768, + .frate = 85, + .lrate = 69, + .prate = 95, + .reg01 = 0x56, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA1_1280_768_60_L, + .hres = 1280, + .vres = 768, + .frate = 60, + .lrate = 47, + .prate = 68, + .reg01 = 0x5a, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_LOW | 0x10, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA1_1280_768_60_H, + .hres = 1280, + .vres = 768, + .frate = 60, + .lrate = 48, + .prate = 80, + .reg01 = 0x68, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA1_1280_768_75, + .hres = 1280, + .vres = 768, + .frate = 75, + .lrate = 60, + .prate = 102, + .reg01 = 0x6b, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA1_1280_768_85, + .hres = 1280, + .vres = 768, + .frate = 85, + .lrate = 69, + .prate = 118, + .reg01 = 0x6b, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGA_1280_1024_60, + .hres = 1280, + .vres = 1024, + .frate = 60, + .lrate = 64, + .prate = 108, + .reg01 = 0x69, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGA_1280_1024_75, + .hres = 1280, + .vres = 1024, + .frate = 75, + .lrate = 80, + .prate = 135, + .reg01 = 0x69, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x28, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGA_1280_1024_85, + .hres = 1280, + .vres = 1024, + .frate = 85, + .lrate = 91, + .prate = 158, + .reg01 = 0x6c, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x28, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGAPLUS_1400_1050_60_L, + .hres = 1400, + .vres = 1050, + .frate = 60, + .lrate = 65, + .prate = 101, + .reg01 = 0x61, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGAPLUS_1400_1050_60_H, + .hres = 1400, + .vres = 1050, + .frate = 60, + .lrate = 65, + .prate = 121, + .reg01 = 0x74, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_MED | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_SXGAPLUS_1400_1050_75, + .hres = 1400, + .vres = 1050, + .frate = 75, + .lrate = 82, + .prate = 156, + .reg01 = 0x76, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA2_1440_900_60_L, + .hres = 1440, + .vres = 900, + .frate = 60, + .lrate = 55, + .prate = 89, + .reg01 = 0x64, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA2_1440_900_60_H, + .hres = 1440, + .vres = 900, + .frate = 60, + .lrate = 56, + .prate = 107, + .reg01 = 0x77, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x18, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA2_1440_900_75, + .hres = 1440, + .vres = 900, + .frate = 75, + .lrate = 71, + .prate = 137, + .reg01 = 0x79, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_WXGA2_1440_900_85, + .hres = 1440, + .vres = 900, + .frate = 85, + .lrate = 80, + .prate = 157, + .reg01 = 0x7a, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_UXGA_1600_1200_60, + .hres = 1600, + .vres = 1200, + .frate = 60, + .lrate = 75, + .prate = 162, + .reg01 = 0x87, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, + .reg04 = 0x00, + .available = TRUE, + }, { + .id = TVP7002_VIDEOI_720_480_30, + .hres = 720, + .vres = 480, + .frate = 30, + .lrate = 15, + .prate = 14, + .reg01 = 0x35, + .reg02 = 0xa0, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOI_720_576_25, + .hres = 720, + .vres = 576, + .frate = 25, + .lrate = 16, + .prate = 14, + .reg01 = 0x36, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_720_480_60, + .hres = 720, + .vres = 480, + .frate = 60, + .lrate = 31, + .prate = 27, + .reg01 = 0x35, + .reg02 = 0xa0, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_720_576_50, + .hres = 720, + .vres = 576, + .frate = 50, + .lrate = 31, + .prate = 27, + .reg01 = 0x36, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_1280_720_60, + .hres = 1280, + .vres = 720, + .frate = 60, + .lrate = 45, + .prate = 74, + .reg01 = 0x67, + .reg02 = 0x20, + .reg03 = TVP7002_VCO_RANGE_MED | 0x20, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_1280_720_50, + .hres = 1280, + .vres = 720, + .frate = 50, + .lrate = 38, + .prate = 74, + .reg01 = 0x7b, + .reg02 = 0xc0, + .reg03 = TVP7002_VCO_RANGE_MED | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOI_1920_1080_60, + .hres = 1920, + .vres = 1080, + .frate = 60, + .lrate = 34, + .prate = 74, + .reg01 = 0x89, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_MED | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOI_1920_1080_50, + .hres = 1920, + .vres = 1080, + .frate = 50, + .lrate = 28, + .prate = 74, + .reg01 = 0xa5, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_MED | 0x10, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_1920_1080_60, + .hres = 1920, + .vres = 1080, + .frate = 60, + .lrate = 68, + .prate = 149, + .reg01 = 0x89, + .reg02 = 0x80, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, + .reg04 = 0x80, + .available = TRUE, + }, { + .id = TVP7002_VIDEOP_1920_1080_50, + .hres = 1920, + .vres = 1080, + .frate = 50, + .lrate = 56, + .prate = 149, + .reg01 = 0xa5, + .reg02 = 0x00, + .reg03 = TVP7002_VCO_RANGE_HIGH | 0x18, + .reg04 = 0x80, + .available = TRUE, + }, +}; + +/* I2C Device ID table */ +static const struct i2c_device_id tvp7002_id[] = { + { "tvp7002", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, tvp7002_id); + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tvp7002", + .probe = tvp7002_probe, + .remove = tvp7002_remove, + .id_table = tvp7002_id, +}; + +/* Device definition */ + +struct tvp7002 { + struct v4l2_subdev sd; + v4l2_std_id video_mode; +}; + +/* Supported controls */ + +static struct v4l2_queryctrl tvp7002_qctrl[] = { + { + .id = V4L2_CID_COARSE_GAIN_R, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for Red channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_COARSE_GAIN_G, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for Green channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_COARSE_GAIN_B, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for Blue channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_FINE_GAIN_R, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for Red channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_FINE_GAIN_G, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for Green channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_FINE_GAIN_B, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for Blue channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_SOG_IN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sync-On-Green input", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_R_IN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red input", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_G_IN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Green input", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_R_IN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue input", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SOG_LPF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sync-On-Green low pass filter", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 3, + .flags = 0, + }, + { + .id = V4L2_CID_CLAMP_LPF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Clamp low pass filter", + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_CLK_IN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Clock input", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_VSYNC_IN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "VSYNC input", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PIXEL_CLK_IN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Pixel clock input", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_HSYNC_IN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "HSYNC input", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SOG_THRS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sync-On-Green threshold", + .minimum = 0, + .maximum = 31, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_B_CLAMP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Toggle Blue clamp", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_G_CLAMP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Toggle Green clamp", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_R_CLAMP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Toggle Red clamp", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_CLAMP_OFF_EN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Enable clamp offset", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_FCTCA, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fine clamp time cnst adj", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_F_CLAMP_GB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fine clamp for Green and Blue", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_F_CLAMP_R, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fine clamp for Red", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_CLAMP_START, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Clamp start", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x32, + .flags = 0, + }, + { + .id = V4L2_CID_CLAMP_W, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Clamp width", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_B_COARSE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue coarse offset", + .minimum = 0, + .maximum = 32, + .step = 1, + .default_value = 0x10, + .flags = 0, + }, + { + .id = V4L2_CID_G_COARSE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Green coarse offset", + .minimum = 0, + .maximum = 32, + .step = 1, + .default_value = 0x10, + .flags = 0, + }, + { + .id = V4L2_CID_R_COARSE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red coarse offset", + .minimum = 0, + .maximum = 32, + .step = 1, + .default_value = 0x10, + .flags = 0, + }, + { + .id = V4L2_CID_B_FINE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue fine offset", + .minimum = 0, + .maximum = 1024, + .step = 1, + .default_value = 512, + .flags = 0, + }, + { + .id = V4L2_CID_G_FINE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Green coarse offset", + .minimum = 0, + .maximum = 1024, + .step = 1, + .default_value = 512, + .flags = 0, + }, + { + .id = V4L2_CID_R_FINE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red coarse offset", + .minimum = 0, + .maximum = 1024, + .step = 1, + .default_value = 512, + .flags = 0, + }, + { + .id = V4L2_CID_ALC_EN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic level control (ALC)", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_ALC_PLACEMENT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "ALC placement", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x5a, + .flags = 0, + }, + { + .id = V4L2_CID_ALC_FILTER_VERT_CF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "ALC vertical coefficient", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 10, + .flags = 0, + }, + { + .id = V4L2_CID_ALC_FILTER_HORZ_CF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "ALC horizontal coefficient", + .minimum = 0, + .maximum = 7, + .step = 1, + .default_value = 3, + .flags = 0, + }, + { + .id = V4L2_CID_CLAMP_ALC_PULSE_RF, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Clamp and ALC pulse reference", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_OUT_CODE_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Output code range", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_OUT_CBCR_ORDER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "YUV CbCr output order", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_OUT_422_444, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "4:4:4/4:2:2 output format", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_OUT_EMB_SYNC_EN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Embedded SYNC enable", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_HSPO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "HSYNC polarity override", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_HSIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "HSYNC input polarity (caution)", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_HSOP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "HSYNC output polarity", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_AHSO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Active HSYNC override", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_AHSS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Active HSYNC select", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_VSOP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "VSYNC output polarity", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_AVSO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Active VSYNC override", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SYNC_AVSS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Active VSYNC select", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_SEEK_MODE_OVRD, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "SYNC mode override", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_FCPD, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Full chip power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_SOG_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Sync-On-Green power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_SLICER_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Slicer power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_REF_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Reference power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_CURRENT_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Current power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_ADC_B_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "ADC Blue channel power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_ADC_G_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "ADC Green channel power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + { + .id = V4L2_CID_PWR_ADC_R_PWDN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "ADC Red channel power down", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + } +}; + +/** V4L2 Operations handlers **/ +static const struct v4l2_subdev_core_ops tvp7002_core_ops = { + .g_chip_ident = tvp7002_g_chip_ident, + .log_status = tvp7002_log_status, + .g_ctrl = tvp7002_g_ctrl, + .s_ctrl = tvp7002_s_ctrl, + .queryctrl = tvp7002_queryctrl, + .s_std = tvp7002_s_std, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tvp7002_g_register, + .s_register = tvp7002_s_register, +#endif +}; + +/* Specific video subsystem operation handlers */ +static const struct v4l2_subdev_video_ops tvp7002_video_ops = { + .querystd = tvp7002_querystd, +}; + +static const struct v4l2_subdev_ops tvp7002_ops = { + .core = &tvp7002_core_ops, + .video = &tvp7002_video_ops, +}; + +/*** Functions ***/ + +/** Register access functions **/ + +/* Read the contents of a register */ +static int tvp7002_read(struct v4l2_subdev *sd, unsigned char addr){ + struct i2c_client *c = v4l2_get_subdevdata(sd); + unsigned char buffer[1]; + int rc; + + buffer[0] = addr; + if (1 != (rc = i2c_master_send(c, buffer, 1))) + v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + + /* Sleep and try once more */ + msleep(10); + + if (1 != (rc = i2c_master_recv(c, buffer, 1))) + v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc); + + v4l2_dbg(2, debug, sd, "tvp7002: read 0x%02x = 0x%02x\n", addr, buffer[0]); + + return (buffer[0]); +} + +/* Write data to a register */ +static int tvp7002_write(struct v4l2_subdev *sd, unsigned char addr, unsigned char value){ + struct i2c_client *c = v4l2_get_subdevdata(sd); + unsigned char buffer[2]; + int rc; + + buffer[0] = addr; + buffer[1] = value; + v4l2_dbg(2, debug, sd, "tvp7002: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]); + + if (2 != (rc = i2c_master_send(c, buffer, 2))){ + v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc); + return -1; + } + + return 0; + +} + +/* Read data in registers withing a range given by [init..end] */ +static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, const u8 end, int max_line){ + int i = 0; + + while (init != (u8)(end + 1)) { + if ((i % max_line) == 0) { + if (i > 0) + printk("\n"); + printk("tvp7002: %s reg 0x%02x = ", s, init); + } + + printk("%02x ", tvp7002_read(sd, init)); + init++; + i++; + } + printk("\n"); +} + +/* Log function for register contents */ +static int tvp7002_log_status(struct v4l2_subdev *sd){ + printk("tvp7002: Chip revision number = 0x%02x\n", + tvp7002_read(sd, TVP7002_CHIP_REV)); + printk("tvp7002: H-PLL feedback divider MSBs and LSBs = 0x%02x, 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_MSBS), + tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_LSBS)); + printk("tvp7002: VCO frequency range selector = 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_CRTL)); + printk("tvp7002: ADC sampling clock phase selector = 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_PHASE_SEL)); + printk("tvp7002: Clamp start = 0x%02x\n", + tvp7002_read(sd, TVP7002_CLAMP_START)); + printk("tvp7002: Clamp width = 0x%02x\n", + tvp7002_read(sd, TVP7002_CLAMP_W)); + printk("tvp7002: HSYNC output width = 0x%02x\n", + tvp7002_read(sd, TVP7002_HSYNC_OUT_W)); + printk("tvp7002: Digital fine grain for Blue channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_B_FINE_GAIN)); + printk("tvp7002: Digital fine grain for Green channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_G_FINE_GAIN)); + printk("tvp7002: Digital fine grain for Red channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_R_FINE_GAIN)); + printk("tvp7002: Digital fine grain offset for Blue channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS)); + printk("tvp7002: Digital fine grain offset for Green channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS)); + printk("tvp7002: Digital fine grain offset for Red channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS)); + printk("tvp7002: Digital fine grain LSB offsets for RGB channels = 0x%02x\n", + tvp7002_read(sd, TVP7002_FINE_OFF_LSBS)); + printk("tvp7002: SYNC control 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_SYNC_CTL_1)); + printk("tvp7002: H-PLL and clamp control = 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_AND_CLAMP_CTL)); + printk("tvp7002: Sync-On-Green threshold = 0x%02x\n", + tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS)); + printk("tvp7002: Sync separator threshold = 0x%02x\n", + tvp7002_read(sd, TVP7002_SYNC_SEPARATOR_THRS)); + printk("tvp7002: H-PLL pre-coast = 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_PRE_COAST)); + printk("tvp7002: H-PLL post-coast = 0x%02x\n", + tvp7002_read(sd, TVP7002_HPLL_POST_COAST)); + printk("tvp7002: Sync detect status = 0x%02x\n", + tvp7002_read(sd, TVP7002_SYNC_DETECT_STAT)); + printk("tvp7002: Output formatter = 0x%02x\n", + tvp7002_read(sd, TVP7002_OUT_FORMATTER)); + printk("tvp7002: Miscelaneous control 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_MISC_CTL_1)); + printk("tvp7002: Miscelaneous control 2 = 0x%02x\n", + tvp7002_read(sd, TVP7002_MISC_CTL_2)); + printk("tvp7002: Miscelaneous control 3 = 0x%02x\n", + tvp7002_read(sd, TVP7002_MISC_CTL_3)); + printk("tvp7002: Input Mux Selector 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_IN_MUX_SEL_1)); + printk("tvp7002: Input Mux Selector 2 = 0x%02x\n", + tvp7002_read(sd, TVP7002_IN_MUX_SEL_2)); + printk("tvp7002: Blue and Green coarse gain = 0x%02x\n", + tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN)); + printk("tvp7002: Red coarse gain = 0x%02x\n", + tvp7002_read(sd, TVP7002_R_COARSE_GAIN)); + printk("tvp7002: Coarse offset for Blue channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_B_COARSE_OFF)); + printk("tvp7002: Coarse offset for Green channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_G_COARSE_OFF)); + printk("tvp7002: Coarse offset for Red channel = 0x%02x\n", + tvp7002_read(sd, TVP7002_R_COARSE_OFF)); + printk("tvp7002: HSYNC leading edge output start = 0x%02x\n", + tvp7002_read(sd, TVP7002_HSOUT_OUT_START)); + printk("tvp7002: Miscelaneous control 4 = 0x%02x\n", + tvp7002_read(sd, TVP7002_MISC_CTL_4)); + printk("tvp7002: Filtered digital ALC output for Blue channel LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_B_DGTL_ALC_OUT_LSBS)); + printk("tvp7002: Filtered digital ALC output for Green channel LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_G_DGTL_ALC_OUT_LSBS)); + printk("tvp7002: Filtered digital ALC output for Red channel LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_R_DGTL_ALC_OUT_LSBS)); + printk("tvp7002: Automatic level control enable = 0x%02x\n", + tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_ENABLE)); + printk("tvp7002: Filtered digital ALC output for RGB channels MSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_DGTL_ALC_OUT_MSBS)); + printk("tvp7002: Automatic level control filter = 0x%02x\n", + tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_FILTER)); + printk("tvp7002: Fine clamp control = 0x%02x\n", + tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL)); + printk("tvp7002: Power control = 0x%02x\n", + tvp7002_read(sd, TVP7002_PWR_CTL)); + printk("tvp7002: ADC setup = 0x%02x\n", + tvp7002_read(sd, TVP7002_ADC_SETUP)); + printk("tvp7002: Coarse clamp control = 0x%02x\n", + tvp7002_read(sd, TVP7002_COARSE_CLAMP_CTL)); + printk("tvp7002: Sync-On-Green clamp = 0x%02x\n", + tvp7002_read(sd, TVP7002_SOG_CLAMP)); + printk("tvp7002: RGB coarse clamp control = 0x%02x\n", + tvp7002_read(sd, TVP7002_RGB_COARSE_CLAMP_CTL)); + printk("tvp7002: Sync-On-Green coarse clamp control = 0x%02x\n", + tvp7002_read(sd, TVP7002_SOG_COARSE_CLAMP_CTL)); + printk("tvp7002: ALC placement = 0x%02x\n", + tvp7002_read(sd, TVP7002_ALC_PLACEMENT)); + printk("tvp7002: Macrovision stripper width = 0x%02x\n", + tvp7002_read(sd, TVP7002_MVIS_STRIPPER_W)); + printk("tvp7002: VSYNC alignment = 0x%02x\n", + tvp7002_read(sd, TVP7002_VSYNC_ALGN)); + printk("tvp7002: Sync bypass = 0x%02x\n", + tvp7002_read(sd, TVP7002_SYNC_BYPASS)); + printk("tvp7002: Lines per frame status MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_L_FRAME_STAT_MSBS), + tvp7002_read(sd, TVP7002_L_FRAME_STAT_LSBS)); + printk("tvp7002: Clocks per line status MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_CLK_L_STAT_MSBS), + tvp7002_read(sd, TVP7002_CLK_L_STAT_LSBS)); + printk("tvp7002: HSYNC width = 0x%02x\n", + tvp7002_read(sd, TVP7002_HSYNC_W)); + printk("tvp7002: VSYNC width = 0x%02x\n", + tvp7002_read(sd, TVP7002_VSYNC_W)); + printk("tvp7002: Line length tolerance = 0x%02x\n", + tvp7002_read(sd, TVP7002_L_LENGTH_TOL)); + printk("tvp7002: Video bandwidth control = 0x%02x\n", + tvp7002_read(sd, TVP7002_VIDEO_BWTH_CTL)); + printk("tvp7002: AVID start pixel MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_AVID_START_PIXEL_MSBS), + tvp7002_read(sd, TVP7002_AVID_START_PIXEL_LSBS)); + printk("tvp7002: AVID stop pixel MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_MSBS), + tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_LSBS)); + printk("tvp7002: VBLK start line offset 0 = 0x%02x\n", + tvp7002_read(sd, TVP7002_VBLK_F_0_START_L_OFF)); + printk("tvp7002: VBLK start line offset 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_VBLK_F_1_START_L_OFF)); + printk("tvp7002: VBLK duration 0 = 0x%02x\n", + tvp7002_read(sd, TVP7002_VBLK_F_0_DURATION)); + printk("tvp7002: VBLK duration 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_VBLK_F_1_DURATION)); + printk("tvp7002: F-bit start line offset 0 = 0x%02x\n", + tvp7002_read(sd, TVP7002_FBIT_F_0_START_L_OFF)); + printk("tvp7002: F-bit start line offset 1 = 0x%02x\n", + tvp7002_read(sd, TVP7002_FBIT_F_1_START_L_OFF)); + printk("tvp7002: YUV Y coefficient for Green MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_LSBS)); + printk("tvp7002: YUV Y coefficient for Blue MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_LSBS)); + printk("tvp7002: YUV Y coefficient for Red MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_LSBS)); + printk("tvp7002: YUV U coefficient for Green MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_U_G_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_U_G_COEF_LSBS)); + printk("tvp7002: YUV U coefficient for Blue MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_U_B_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_U_B_COEF_LSBS)); + printk("tvp7002: YUV U coefficient for Red MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_U_R_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_U_R_COEF_LSBS)); + printk("tvp7002: YUV V coefficient for Green MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_V_G_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_V_G_COEF_LSBS)); + printk("tvp7002: YUV V coefficient for Blue MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_V_B_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_V_B_COEF_LSBS)); + printk("tvp7002: YUV V coefficient for Red MSBs and LSBs = 0x%02x LSBs = 0x%02x\n", + tvp7002_read(sd, TVP7002_YUV_V_R_COEF_MSBS), + tvp7002_read(sd, TVP7002_YUV_V_R_COEF_LSBS)); + + return 0; +} + +/** Device access functions **/ + +/* Obtain parent structure */ +static struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd){ + return container_of(sd, struct tvp7002, sd); +} + +/* Get chip identification information */ +static int tvp7002_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip){ + int rev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + + rev = tvp7002_read(sd, TVP7002_CHIP_REV); + + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, rev); +} + +/* Initialize for default values */ +static int tvp7002_write_inittab(struct v4l2_subdev *sd, const struct i2c_reg_value *regs){ + int i; + /* Initialize the first (defined) registers */ + while (regs->reg != 0x5c) { + tvp7002_write(sd, regs->reg, regs->value); + regs++; + } + /* Initialize the last (undefined) registers */ + for (i = 0x5c; i <= 0xff; i++) + tvp7002_write(sd, i, 0x00); + + return 0; +} + +/* Set video mode */ +static int tvp7002_set_video_mode(struct v4l2_subdev *sd, int sdf){ + /* If this configuration exists but is not available, signal correspondingly */ + if (!tvp7002_resolutions[sdf].available){ + v4l2_err(sd, "tvp7002: Standard Display Format is not available in current implementation\n"); + return -1; + } + + /* Print specific information about current format */ + printk("tvp7002: Setting standard display format...\n"); + printk("tvp7002: hres = %d vres=%d frate=%d lrate=%d prate=%d\n", + tvp7002_resolutions[sdf].hres, + tvp7002_resolutions[sdf].vres, + tvp7002_resolutions[sdf].frate, + tvp7002_resolutions[sdf].lrate, + tvp7002_resolutions[sdf].prate); + /* Set registers accordingly */ + tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_MSBS, tvp7002_resolutions[sdf].reg01); + tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_LSBS, tvp7002_resolutions[sdf].reg02); + tvp7002_write(sd, TVP7002_HPLL_CRTL, tvp7002_resolutions[sdf].reg03); + tvp7002_write(sd, TVP7002_HPLL_PHASE_SEL, tvp7002_resolutions[sdf].reg04); + + /* Now, the tricky part for SD modes */ + if (IS_SD_MODE(sdf)){ + // Set registers 05h, 06h, 12h, 13h, 1Ah, 22h, 31h + if (sdf < TVP7002_VIDEOP_720_480_60){ + tvp7002_write(sd, TVP7002_CLAMP_START, 0x06); + tvp7002_write(sd, TVP7002_CLAMP_W, 0x10); + tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x03); + tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x03); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0x17); + if (sdf < TVP7002_VIDEOP_720_480_60){ + tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x0c); + tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x24); + } + else { + tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x0a); + tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x12); + } + tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x08); + tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x18); + } + else { + tvp7002_write(sd, TVP7002_CLAMP_START, 0x32); + tvp7002_write(sd, TVP7002_CLAMP_W, 0x20); + tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x01); + tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x00); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0xc7); + if(sdf < TVP7002_VIDEOI_1920_1080_60) + tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x35); + else + tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x39); + tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x00); + tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x5a); + if(sdf < TVP7002_VIDEOP_1920_1080_60) + tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x07); + else + tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x03); + } + // Set registers 2Ch and 3Fh + if (sdf < TVP7002_VIDEOP_1920_1080_60){ + tvp7002_write(sd, TVP7002_ADC_SETUP, 0x50); + tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x0f); + } + else { + tvp7002_write(sd, TVP7002_ADC_SETUP, 0x80); + tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x00); + } + // Set up registers that hold the same value regardless + // of the SD mode + tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, 0x5d); + tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); + tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); + tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); + tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); + tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06);; + tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); + tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); + tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); + tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); + tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); + } + else if ( IS_XGA60_MODE(sdf) ){ + tvp7002_write(sd, TVP7002_CLAMP_START, 0x06); + tvp7002_write(sd, TVP7002_CLAMP_W, 0x10); + tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, 0x58); + tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); + tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x01); + tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x00); + tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); + tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); + tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0xc7); + tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x0d); + tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x00); + tvp7002_write(sd, TVP7002_ADC_SETUP, 0x50); + tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x18); + // Macrovision strip width register is set to its default value + tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); + tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); + tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x00); + } + + return 0; +} + +/* Get video mode */ +static int tvp7002_get_video_mode(struct v4l2_subdev *sd){ + int reg01, reg02, reg03; + // Read the value in the first register (reg01) + // and recognize first all unique identifiers, + // then those differentiable by the value of their + // second register and finally those by the value + // of the third register. This is not elegant and + // needs to be changed in a more efficient way. + reg01 = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_MSBS); + reg02 = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_LSBS); + reg03 = tvp7002_read(sd, TVP7002_HPLL_CRTL); + + switch(reg01){ + case 0x32: + return TVP7002_VGA_640_480_60; + case 0x34: + if (reg02 == 0x00) + return TVP7002_VGA_640_480_73; + else if (reg02 == 0x80) + return TVP7002_VGA_640_480_75; + else if (reg03 == 0x60) + return TVP7002_VGA_640_480_85; + case 0x40: + return TVP7002_SVGA_800_600_56; + case 0x41: + if (reg02 == 0x00) + return TVP7002_SVGA_800_600_72; + else + return TVP7002_SVGA_800_600_85; + // In the documentation, based on the value of registers 0x01, 0x02 and 0x03 there is + // no current way of identifying the appropriate mode (probably an error on the device's + // documentation). First listed, first served. + case 0x42: + if (reg02 == 0x00) + return TVP7002_SVGA_800_600_60; + else + return TVP7002_SVGA_800_600_75; + case 0x54: + return TVP7002_XGA_1024_768_60; + case 0x53: + return TVP7002_XGA_1024_768_70; + case 0x52: + return TVP7002_XGA_1024_768_75; + case 0x56: + return TVP7002_XGA_1024_768_85; + case 0x5a: + return TVP7002_WXGA1_1280_768_60_L; + case 0x68: + return TVP7002_WXGA1_1280_768_60_H; + case 0x6a: + return TVP7002_WXGA1_1280_768_75; + case 0x6b: + return TVP7002_WXGA1_1280_768_85; + case 0x69: + if (reg03 == 0xa0) + return TVP7002_SXGA_1280_1024_60; + else + return TVP7002_SXGA_1280_1024_75; + case 0x6c: + return TVP7002_SXGA_1280_1024_85; + case 0x61: + return TVP7002_SXGAPLUS_1400_1050_60_L; + case 0x74: + return TVP7002_SXGAPLUS_1400_1050_60_H; + case 0x76: + return TVP7002_SXGAPLUS_1400_1050_75; + case 0x64: + return TVP7002_WXGA2_1440_900_60_L; + case 0x77: + return TVP7002_WXGA2_1440_900_60_H; + case 0x79: + return TVP7002_WXGA2_1440_900_75; + case 0x7a: + return TVP7002_WXGA2_1440_900_85; + case 0x87: + return TVP7002_UXGA_1600_1200_60; + case 0x35: + if (reg02 == 0xa0) + return TVP7002_VIDEOI_720_480_30; + else + return TVP7002_VIDEOI_720_576_25; + case 0x36: + if (reg02 == 0xa0) + return TVP7002_VIDEOP_720_480_60; + else + return TVP7002_VIDEOP_720_576_50; + case 0x67: + return TVP7002_VIDEOP_1280_720_60; + case 0x7b: + return TVP7002_VIDEOP_1280_720_50; + case 0x89: + if (reg03 == 0x98) + return TVP7002_VIDEOI_1920_1080_60; + else + return TVP7002_VIDEOP_1920_1080_60; + case 0xa5: + if (reg03 == 0x90) + return TVP7002_VIDEOI_1920_1080_50; + else + return TVP7002_VIDEOP_1920_1080_50; + } +} + +/* Set standard video definition + * + * This will be changed with the following + * iteration of v4l2 HD definitions */ +static int tvp7002_s_std(struct v4l2_subdev *sd, v4l2_std_id std){ + struct tvp7002 *decoder = to_tvp7002(sd); + int vmd = 0; + + decoder->video_mode = std; + vmd = (int)(std & ~V4L2_STD_TVP7002_BASE_STD); + + v4l2_dbg(1, debug, sd, "Set video std mode to %d.\n", vmd); + tvp7002_set_video_mode(sd, vmd); + + return 0; +} + +static int tvp7002_querystd(struct v4l2_subdev *sd, v4l2_std_id *std){ + (*std) = tvp7002_get_video_mode(sd); + + return 0; +}; + +/* Get a control */ +static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl){ + v4l2_dbg(1, debug, sd, "tvp7002: g_ctrl called\n"); + + switch (ctrl->id) { + case V4L2_CID_COARSE_GAIN_R: + ctrl->value = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + return 0; + case V4L2_CID_COARSE_GAIN_G: + ctrl->value = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + return 0; + case V4L2_CID_COARSE_GAIN_B: + ctrl->value = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + return 0; + case V4L2_CID_FINE_GAIN_R: + ctrl->value = tvp7002_read(sd, TVP7002_R_FINE_GAIN); + return 0; + case V4L2_CID_FINE_GAIN_G: + ctrl->value = (tvp7002_read(sd, TVP7002_G_FINE_GAIN) >> 4) & 0x0f; + return 0; + case V4L2_CID_FINE_GAIN_B: + ctrl->value = tvp7002_read(sd, TVP7002_B_FINE_GAIN) & 0x0f; + return 0; + case V4L2_CID_SOG_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_1) >> 6) & 0x03; + return 0; + case V4L2_CID_R_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_1) >> 4) & 0x03; + return 0; + case V4L2_CID_G_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_1) >> 2) & 0x03; + return 0; + case V4L2_CID_B_IN: + ctrl->value = tvp7002_read(sd, TVP7002_IN_MUX_SEL_1) & 0x03; + return 0; + case V4L2_CID_SOG_LPF: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) >> 6) & 0x03; + return 0; + case V4L2_CID_CLAMP_LPF: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) >> 4) & 0x03; + return 0; + case V4L2_CID_CLK_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) >> 3) & 0x01; + return 0; + case V4L2_CID_VSYNC_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) >> 2) & 0x01; + return 0; + case V4L2_CID_PIXEL_CLK_IN: + ctrl->value = (tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) >> 1) & 0x01; + return 0; + case V4L2_CID_HSYNC_IN: + ctrl->value = tvp7002_read(sd, TVP7002_IN_MUX_SEL_2) & 0x01; + return 0; + case V4L2_CID_SOG_THRS: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS) >> 3) & 0x1f; + return 0; + case V4L2_CID_B_CLAMP: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS) >> 2) & 0x01; + return 0; + case V4L2_CID_G_CLAMP: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS) >> 1) & 0x01; + return 0; + case V4L2_CID_R_CLAMP: + ctrl->value = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS) & 0x01; + return 0; + case V4L2_CID_CLAMP_OFF_EN: + ctrl->value = (tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL) >> 7) & 0x01; + return 0; + case V4L2_CID_FCTCA: + ctrl->value = ((tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL >> 3) & 0x03) == 0x03) ? 1 : 0; + return 0; + case V4L2_CID_F_CLAMP_GB: + ctrl->value = (tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL) >> 1) & 0x01; + return 0; + case V4L2_CID_F_CLAMP_R: + return tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, ctrl->value & 0x01); + case V4L2_CID_CLAMP_START: + ctrl->value = tvp7002_read(sd, TVP7002_CLAMP_START) & 0xff; + return 0; + case V4L2_CID_CLAMP_W: + ctrl->value = tvp7002_read(sd, TVP7002_CLAMP_W) & 0xff; + return 0; + case V4L2_CID_B_COARSE_OFF: + ctrl->value = tvp7002_read(sd, TVP7002_B_COARSE_OFF) & 0x3f; + return 0; + case V4L2_CID_G_COARSE_OFF: + ctrl->value = tvp7002_read(sd, TVP7002_G_COARSE_OFF) & 0x3f; + return 0; + case V4L2_CID_R_COARSE_OFF: + ctrl->value = tvp7002_read(sd, TVP7002_R_COARSE_OFF) & 0x3f; + return 0; + case V4L2_CID_B_FINE_OFF: + ctrl->value = (tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS) << 2) | + (tvp7002_read(sd, TVP7002_FINE_OFF_LSBS) & 0x03); + return 0; + case V4L2_CID_G_FINE_OFF: + ctrl->value = (tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS) << 2) | + ((tvp7002_read(sd, TVP7002_FINE_OFF_LSBS) >> 2) & 0x03); + return 0; + case V4L2_CID_R_FINE_OFF: + ctrl->value = (tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS) << 2) | + ((tvp7002_read(sd, TVP7002_FINE_OFF_LSBS) >> 4) & 0x03); + return 0; + case V4L2_CID_ALC_EN: + ctrl->value = (tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_ENABLE) >> 7) & 0x01; + return 0; + case V4L2_CID_ALC_PLACEMENT: + ctrl->value = tvp7002_read(sd, TVP7002_ALC_PLACEMENT) & 0xff; + return 0; + case V4L2_CID_ALC_FILTER_VERT_CF: + ctrl->value = (tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_ENABLE) >> 3) & 0x0f; + return 0; + case V4L2_CID_ALC_FILTER_HORZ_CF: + ctrl->value = tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_FILTER) & 0x07; + return 0; + case V4L2_CID_CLAMP_ALC_PULSE_RF: + ctrl->value = (tvp7002_read(sd, TVP7002_OUT_FORMATTER) >> 3) & 0x01; + return 0; + case V4L2_CID_OUT_CODE_RANGE: + ctrl->value = (tvp7002_read(sd, TVP7002_OUT_FORMATTER) >> 5) & 0x03; + return 0; + case V4L2_CID_OUT_CBCR_ORDER: + ctrl->value = (tvp7002_read(sd, TVP7002_OUT_FORMATTER) >> 2) & 0x01; + return 0; + case V4L2_CID_OUT_422_444: + ctrl->value = (tvp7002_read(sd, TVP7002_OUT_FORMATTER) >> 1) & 0x01; + return 0; + case V4L2_CID_OUT_EMB_SYNC_EN: + ctrl->value = tvp7002_read(sd, TVP7002_OUT_FORMATTER) & 0x01; + return 0; + case V4L2_CID_SYNC_HSPO: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 7) & 0x01; + return 0; + case V4L2_CID_SYNC_HSIP: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 6) & 0x01; + return 0; + case V4L2_CID_SYNC_HSOP: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 5) & 0x01; + return 0; + case V4L2_CID_SYNC_AHSO: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 4) & 0x01; + return 0; + case V4L2_CID_SYNC_AHSS: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 3) & 0x01; + return 0; + case V4L2_CID_SYNC_VSOP: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 2) & 0x01; + return 0; + case V4L2_CID_SYNC_AVSO: + ctrl->value = (tvp7002_read(sd, TVP7002_SYNC_CTL_1) >> 1) & 0x01; + return 0; + case V4L2_CID_SYNC_AVSS: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, ctrl->value & 0x01); + case V4L2_CID_SEEK_MODE_OVRD: + ctrl->value = (tvp7002_read(sd, TVP7002_HPLL_AND_CLAMP_CTL) >> 2) & 0x01; + return 0; + case V4L2_CID_PWR_FCPD: + ctrl->value = (tvp7002_read(sd, TVP7002_HPLL_AND_CLAMP_CTL) >> 1) & 0x01; + return 0; + case V4L2_CID_PWR_SOG_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 6) & 0x01; + return 0; + case V4L2_CID_PWR_SLICER_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 5) & 0x01; + return 0; + case V4L2_CID_PWR_REF_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 4) & 0x01; + return 0; + case V4L2_CID_PWR_CURRENT_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 3) & 0x01; + return 0; + case V4L2_CID_PWR_ADC_B_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 2) & 0x01; + return 0; + case V4L2_CID_PWR_ADC_G_PWDN: + ctrl->value = (tvp7002_read(sd, TVP7002_PWR_CTL) >> 1) & 0x01; + return 0; + case V4L2_CID_PWR_ADC_R_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, ctrl->value & 0x01); + } + + return -EINVAL; +} + +/* Set a control */ +static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl){ + u8 i, n; + n = ARRAY_SIZE(tvp7002_qctrl); + + for (i = 0; i < n; i++) { + if (ctrl->id != tvp7002_qctrl[i].id) + continue; + + if (ctrl->value < tvp7002_qctrl[i].minimum || ctrl->value > tvp7002_qctrl[i].maximum) + return -ERANGE; + v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", ctrl->id, ctrl->value); + break; + } + + switch (ctrl->id) { + case V4L2_CID_COARSE_GAIN_R: + return tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, ctrl->value & 0xff); + case V4L2_CID_COARSE_GAIN_G: + return tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, (ctrl->value << 4) & 0xf0); + case V4L2_CID_COARSE_GAIN_B: + return tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, ctrl->value& 0x0f); + case V4L2_CID_FINE_GAIN_R: + return tvp7002_write(sd, TVP7002_R_FINE_GAIN, ctrl->value & 0xff); + case V4L2_CID_FINE_GAIN_G: + return tvp7002_write(sd, TVP7002_G_FINE_GAIN, (ctrl->value << 4) & 0xf0); + case V4L2_CID_FINE_GAIN_B: + return tvp7002_write(sd, TVP7002_B_FINE_GAIN, ctrl->value& 0x0f); + case V4L2_CID_SOG_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, (ctrl->value << 6)& 0xc0); + case V4L2_CID_R_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, (ctrl->value << 4)& 0x30); + case V4L2_CID_G_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, (ctrl->value << 2)& 0x0c); + case V4L2_CID_B_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, ctrl->value & 0x03); + case V4L2_CID_SOG_LPF: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, (ctrl->value << 6) & 0xc0); + case V4L2_CID_CLAMP_LPF: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, (ctrl->value << 4) & 0x30); + case V4L2_CID_CLK_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, (ctrl->value << 3) & 0x08); + case V4L2_CID_VSYNC_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, (ctrl->value << 2) & 0x04); + case V4L2_CID_PIXEL_CLK_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, (ctrl->value << 1) & 0x02); + case V4L2_CID_HSYNC_IN: + return tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, ctrl->value & 0x01); + case V4L2_CID_SOG_THRS: + return tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, (ctrl->value << 3) & 0xf8); + case V4L2_CID_B_CLAMP: + return tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, (ctrl->value << 2) & 0x04); + case V4L2_CID_G_CLAMP: + return tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, (ctrl->value << 1) & 0x02); + case V4L2_CID_R_CLAMP: + return tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, ctrl->value & 0x01); + case V4L2_CID_CLAMP_OFF_EN: + return tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, (ctrl->value << 7) & 0x80); + case V4L2_CID_FCTCA: + return tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, ((ctrl->value == 0 ? 0x00 : 0x03) << 3) & 0x0c); + case V4L2_CID_F_CLAMP_GB: + return tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, (ctrl->value << 1) & 0x02); + case V4L2_CID_F_CLAMP_R: + return tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, ctrl->value & 0x01); + case V4L2_CID_CLAMP_START: + return tvp7002_write(sd, TVP7002_CLAMP_START, ctrl->value & 0xff); + case V4L2_CID_CLAMP_W: + return tvp7002_write(sd, TVP7002_CLAMP_W, ctrl->value & 0xff); + case V4L2_CID_B_COARSE_OFF: + return tvp7002_write(sd, TVP7002_B_COARSE_OFF, ctrl->value & 0x3f); + case V4L2_CID_G_COARSE_OFF: + return tvp7002_write(sd, TVP7002_G_COARSE_OFF, ctrl->value & 0x3f); + case V4L2_CID_R_COARSE_OFF: + return tvp7002_write(sd, TVP7002_R_COARSE_OFF, ctrl->value & 0x3f); + case V4L2_CID_B_FINE_OFF: + return tvp7002_write(sd, TVP7002_B_FINE_OFF_MSBS, (ctrl->value & 0xff) >> 2) + + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, ctrl->value & 0x03); + case V4L2_CID_G_FINE_OFF: + return tvp7002_write(sd, TVP7002_G_FINE_OFF_MSBS, (ctrl->value & 0xff) >> 2) + + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, (ctrl->value & 0x03) << 2); + case V4L2_CID_R_FINE_OFF: + return tvp7002_write(sd, TVP7002_R_FINE_OFF_MSBS, (ctrl->value & 0xff) >> 2) + + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, (ctrl->value & 0x03) << 4); + case V4L2_CID_ALC_EN: + return tvp7002_write(sd, TVP7002_AUTO_LVL_CTL_ENABLE, (ctrl->value << 7) & 0x80); + case V4L2_CID_ALC_PLACEMENT: + return tvp7002_write(sd, TVP7002_ALC_PLACEMENT, ctrl->value & 0xff); + case V4L2_CID_ALC_FILTER_VERT_CF: + return tvp7002_write(sd, TVP7002_AUTO_LVL_CTL_FILTER, (ctrl->value << 3) & 0x78); + case V4L2_CID_ALC_FILTER_HORZ_CF: + return tvp7002_write(sd, TVP7002_AUTO_LVL_CTL_FILTER, ctrl->value & 0x07); + case V4L2_CID_CLAMP_ALC_PULSE_RF: + return tvp7002_write(sd, TVP7002_OUT_FORMATTER, (ctrl->value << 3) & 0x08); + case V4L2_CID_OUT_CODE_RANGE: + return tvp7002_write(sd, TVP7002_OUT_FORMATTER, (ctrl->value << 5) & 0x60); + case V4L2_CID_OUT_CBCR_ORDER: + return tvp7002_write(sd, TVP7002_OUT_FORMATTER, (ctrl->value << 2) & 0x04); + case V4L2_CID_OUT_422_444: + return tvp7002_write(sd, TVP7002_OUT_FORMATTER, (ctrl->value << 1) & 0x02); + case V4L2_CID_OUT_EMB_SYNC_EN: + return tvp7002_write(sd, TVP7002_OUT_FORMATTER, ctrl->value & 0x01); + case V4L2_CID_SYNC_HSPO: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 7) & 0x80); + case V4L2_CID_SYNC_HSIP: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 6) & 0x40); + case V4L2_CID_SYNC_HSOP: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 5) & 0x20); + case V4L2_CID_SYNC_AHSO: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 4) & 0x08); + case V4L2_CID_SYNC_AHSS: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 3) & 0x06); + case V4L2_CID_SYNC_VSOP: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 2) & 0x04); + case V4L2_CID_SYNC_AVSO: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, (ctrl->value << 1) & 0x02); + case V4L2_CID_SYNC_AVSS: + return tvp7002_write(sd, TVP7002_SYNC_CTL_1, ctrl->value & 0x01); + case V4L2_CID_SEEK_MODE_OVRD: + return tvp7002_write(sd, TVP7002_HPLL_AND_CLAMP_CTL, (ctrl->value << 2) & 0x04); + case V4L2_CID_PWR_FCPD: + return tvp7002_write(sd, TVP7002_HPLL_AND_CLAMP_CTL, (ctrl->value << 1) & 0x02); + case V4L2_CID_PWR_SOG_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 6) & 0x40); + case V4L2_CID_PWR_SLICER_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 5) & 0x20); + case V4L2_CID_PWR_REF_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 4) & 0x08); + case V4L2_CID_PWR_CURRENT_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 3) & 0x06); + case V4L2_CID_PWR_ADC_B_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 2) & 0x04); + case V4L2_CID_PWR_ADC_G_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, (ctrl->value << 1) & 0x02); + case V4L2_CID_PWR_ADC_R_PWDN: + return tvp7002_write(sd, TVP7002_PWR_CTL, ctrl->value & 0x01); + } + + return -EINVAL; +} + +/* IOCTL-handled request: get the value of a register */ +static int tvp7002_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg){ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + reg->val = tvp7002_read(sd, reg->reg & 0xff); + reg->size = 1; + return 0; +} + +/* IOCTL-handled request: set the value of a register */ +static int tvp7002_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg){ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); + return 0; +} + +/* Query for a control */ +static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc){ + int i; + + v4l2_dbg(1, debug, sd, "tvp7002: queryctrl called\n"); + + for (i = 0; i < ARRAY_SIZE(tvp7002_qctrl); i++) + if (qc->id && qc->id == tvp7002_qctrl[i].id) { + memcpy(qc, &(tvp7002_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + +/* Reset tvp7002 chip */ +static int tvp7002_reset(struct v4l2_subdev *sd, u32 val){ + u8 rev; + + rev = tvp7002_read(sd, TVP7002_CHIP_REV); + + if (rev == 0x02) + v4l2_info(sd, "tvp7002 rev. %02x detected.\n", rev); + + else { + v4l2_info(sd, "*** Unknown revision of tvp7002 chip detected.\n"); + v4l2_info(sd, "*** Revision number is %02x\n", rev); + } + + /* Initializes TVP7002 to its default values */ + return tvp7002_write_inittab(sd, tvp7002_init_default); +}; + +/* Probe device */ +static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id){ + struct tvp7002 *core; + struct v4l2_subdev *sd; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(c->adapter, + I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -EIO; + + core = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); + if (!core) { + return -ENOMEM; + } + sd = &core->sd; + v4l2_i2c_subdev_init(sd, c, &tvp7002_ops); + v4l_info(c, "tvp7002 found @ 0x%02x (%s)\n", + c->addr << 1, c->adapter->name); + + core->video_mode = TVP7002_VGA_640_480_60; + + if (debug > 1) + tvp7002_log_status(sd); + + return 0; +} + +/* Remove device */ +static int tvp7002_remove(struct i2c_client *c){ + struct v4l2_subdev *sd = i2c_get_clientdata(c); + + v4l2_dbg(1, debug, sd, "tvp7002.c: removing tvp7002 adapter on address 0x%x\n", c->addr << 1); + + v4l2_device_unregister_subdev(sd); + kfree(to_tvp7002(sd)); + return 0; +} + diff --git a/drivers/media/video/tvp7002_reg.h b/drivers/media/video/tvp7002_reg.h new file mode 100644 index 0000000..8db4104 --- /dev/null +++ b/drivers/media/video/tvp7002_reg.h @@ -0,0 +1,159 @@ +/* + * TVP7002 Triple 8-/10-BIT 165-/110-MSPS Video and Graphics Digitizer + * with Horizontal PLL registers + * + * Copyright (C) 2009 Santiago Nunez-Corrales (santiago.nunez@ridgerun.com) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* Naming conventions + * ------------------ + * + * FDBK: Feedback + * DIV: Divider + * CTL: Control + * SEL: Select + * IN: Input + * OUT: Output + * R: Red + * G: Green + * B: Blue + * OFF: Offset + * THRS: Threshold + * DGTL: Digital + * LVL: Level + * PWR: Power + * MVIS: Macrovision + * W: Width + * H: Height + * ALGN: Alignment + * CLK: Clocks + * TOL: Tolerance + * BWTH: Bandwidth + * COEF: Coefficient + * STAT: Status + * AUTO: Automatic + * FLD: Field + * L: Line + */ + + +#define TVP7002_CHIP_REV 0x00 // Chip revision number +#define TVP7002_HPLL_FDBK_DIV_MSBS 0x01 // Controls the 12-bit horizontal PLL feedback divider value that determines + // the number of pixels per line +#define TVP7002_HPLL_FDBK_DIV_LSBS 0x02 // Controls the 12-bit horizontal PLL feedback divider value that determines + // the number of pixels per line +#define TVP7002_HPLL_CRTL 0x03 // Selects VCO frequency range +#define TVP7002_HPLL_PHASE_SEL 0x04 // ADC sampling clock phase select +#define TVP7002_CLAMP_START 0x05 // Positions the clamp signal an integer number of clock periods after the + // HSYNC signal +#define TVP7002_CLAMP_W 0x06 // Sets the width in pixels for the fine clamp +#define TVP7002_HSYNC_OUT_W 0x07 // Sets the width in pixels for HSYNC output +#define TVP7002_B_FINE_GAIN 0x08 // 8-bit fine digital gain (contrast) for Blue channel (applied after + // the ADC) +#define TVP7002_G_FINE_GAIN 0x09 // 8-bit fine digital gain (contrast) for Green channel (applied after + // the ADC) +#define TVP7002_R_FINE_GAIN 0x0a // 8-bit fine digital gain (contrast) for Red channel (applied after + // the ADC) +#define TVP7002_B_FINE_OFF_MSBS 0x0b // Eight MSBs of 10-bit fine digital offset (brightness) for Blue channel + // (applied after ADC) +#define TVP7002_G_FINE_OFF_MSBS 0x0c // Eight MSBs of 10-bit fine digital offset (brightness) for Green channel + // (applied after ADC) +#define TVP7002_R_FINE_OFF_MSBS 0x0d // Eight MSBs of 10-bit fine digital offset (brightness) for Red channel + // (applied after ADC) +#define TVP7002_SYNC_CTL_1 0x0e // Sync control register 1 +#define TVP7002_HPLL_AND_CLAMP_CTL 0x0f // H-PLL and Clamp functionality control register +#define TVP7002_SYNC_ON_G_THRS 0x10 // Sets the voltage level of the SOG slicer comparator +#define TVP7002_SYNC_SEPARATOR_THRS 0x11 // Sets how many internal clock reference periods the sync separator counts + // to before toggling high or low +#define TVP7002_HPLL_PRE_COAST 0x12 // Sets the number of HSYNC periods that coast becomes active prior to + // VSYNC leading edge +#define TVP7002_HPLL_POST_COAST 0x13 // Sets the number of HSYNC periods that coast stays active following VSYNC + // trailing edge +#define TVP7002_SYNC_DETECT_STAT 0x14 // Sync Detect Status +#define TVP7002_OUT_FORMATTER 0x15 // Sets output decoding parameters +#define TVP7002_MISC_CTL_1 0x16 // Miscelaneous functions control 1 +#define TVP7002_MISC_CTL_2 0x17 // Miscelaneous functions control 2 +#define TVP7002_MISC_CTL_3 0x18 // Miscelaneous functions control 3 +#define TVP7002_IN_MUX_SEL_1 0x19 // Input Mux Select 1 +#define TVP7002_IN_MUX_SEL_2 0x1a // Input Mux Select 2 +#define TVP7002_B_AND_G_COARSE_GAIN 0x1b // Coarse analog gain for Blue and Green +#define TVP7002_R_COARSE_GAIN 0x1c // Coarse analog gain for Red +#define TVP7002_FINE_OFF_LSBS 0x1d // Fine offset for RGB +#define TVP7002_B_COARSE_OFF 0x1e // 6-bit coarse analog offset for Blue channel (applied before ADC) +#define TVP7002_G_COARSE_OFF 0x1f // 6-bit coarse analog offset for Green channel (applied before ADC) +#define TVP7002_R_COARSE_OFF 0x20 // 6-bit coarse analog offset for Red channel (applied before ADC) +#define TVP7002_HSOUT_OUT_START 0x21 // Adjusts the leading edge of the HSYNC output relative to the leading edge + // of the HSYNC input in pixel or clock cycles +#define TVP7002_MISC_CTL_4 0x22 // Miscelaneous functions control 4 +#define TVP7002_B_DGTL_ALC_OUT_LSBS 0x23 // Eight LSBs of 10-bit filtered digital ALC output for Blue channel +#define TVP7002_G_DGTL_ALC_OUT_LSBS 0x24 // Eight LSBs of 10-bit filtered digital ALC output for Green channel +#define TVP7002_R_DGTL_ALC_OUT_LSBS 0x25 // Eight LSBs of 10-bit filtered digital ALC output for Red channel +#define TVP7002_AUTO_LVL_CTL_ENABLE 0x26 // Active-high automatic level control (ALC) enable +#define TVP7002_DGTL_ALC_OUT_MSBS 0x27 // Two LSBs of 10-bit filtered digital ALC output for RGB channels +#define TVP7002_AUTO_LVL_CTL_FILTER 0x28 // Automatic Level Control Filter + +/* Reserved 0x29*/ + +#define TVP7002_FINE_CLAMP_CTL 0x2a // Fine clamp control +#define TVP7002_PWR_CTL 0x2b // Power control +#define TVP7002_ADC_SETUP 0x2c // ADC setup +#define TVP7002_COARSE_CLAMP_CTL 0x2d // Coarse clamp control +#define TVP7002_SOG_CLAMP 0x2e // SOG Clamp +#define TVP7002_RGB_COARSE_CLAMP_CTL 0x2f // RGB channel coarse clamp leakage current switch +#define TVP7002_SOG_COARSE_CLAMP_CTL 0x30 // SOG coarse clamp leakage current switch +#define TVP7002_ALC_PLACEMENT 0x31 // Positions the ALC signal an integer number of clock periods after either + // the leading edge or the trailing edge (default) of the HSYNC signal +/* Reserved 0x32 */ + +/* Reserved 0x33 */ + +#define TVP7002_MVIS_STRIPPER_W 0x34 // Macrovision Stripper Width +#define TVP7002_VSYNC_ALGN 0x35 // Specifies the number of pixels that the leading edge of the VSYNC output + // should be delayed or advanced relative to the leading edge of the HSYNC + // output +#define TVP7002_SYNC_BYPASS 0x36 // Sync bypass +#define TVP7002_L_FRAME_STAT_LSBS 0x37 // Lines per frame status LSBs +#define TVP7002_L_FRAME_STAT_MSBS 0x38 // Lines per frame statis MSBs +#define TVP7002_CLK_L_STAT_LSBS 0x39 // Clocks per line status LSBs +#define TVP7002_CLK_L_STAT_MSBS 0x3a // Clocks per line status MSBs +#define TVP7002_HSYNC_W 0x3b // Number of clock cycles between the leading and trailing edges of the + // HSYNC input +#define TVP7002_VSYNC_W 0x3c // Number of clock cycles between the leading and trailing edges of the + // VSYNC input +#define TVP7002_L_LENGTH_TOL 0x3d // Controls sensitivity to HSYNC input stability when using either the + // internal or external clock reference + +/* Reserved 0x3e */ + +#define TVP7002_VIDEO_BWTH_CTL 0x3f // Selectable low-pass filter settings for controlling the analog + // Video Bandwidth Control +#define TVP7002_AVID_START_PIXEL_LSBS 0x40 // AVID Start Pixel LSBs +#define TVP7002_AVID_START_PIXEL_MSBS 0x41 // AVID Start Pixel MSBs +#define TVP7002_AVID_STOP_PIXEL_LSBS 0x42 // AVID Stop Pixel LSBs +#define TVP7002_AVID_STOP_PIXEL_MSBS 0x43 // AVID Stop Pixel MSBs +#define TVP7002_VBLK_F_0_START_L_OFF 0x44 // VBLK start line offset for field 0 relative to the leading edge of VSYNC +#define TVP7002_VBLK_F_1_START_L_OFF 0x45 // VBLK start line offset for field 1 relative to the leading edge of VSYNC +#define TVP7002_VBLK_F_0_DURATION 0x46 // VBLK duration in lines for field 0 +#define TVP7002_VBLK_F_1_DURATION 0x47 // VBLK duration in lines for field 1 +#define TVP7002_FBIT_F_0_START_L_OFF 0x48 // F-bit Field 0 start line offset relative to the leading edge of VSYNC +#define TVP7002_FBIT_F_1_START_L_OFF 0x49 // F-bit Field 1 start line offset relative to the leading edge of VSYNC +#define TVP7002_YUV_Y_G_COEF_LSBS 0x4a // 16-bit G’ coefficient MSB for Y LSBS +#define TVP7002_YUV_Y_G_COEF_MSBS 0x4b // 16-bit G’ coefficient MSB for Y MSBS +#define TVP7002_YUV_Y_B_COEF_LSBS 0x4c // 16-bit B’ coefficient MSB for Y LSBS +#define TVP7002_YUV_Y_B_COEF_MSBS 0x4d // 16-bit B’ coefficient MSB for Y MSBS +#define TVP7002_YUV_Y_R_COEF_LSBS 0x4e // 16-bit R’ coefficient MSB for Y LSBS +#define TVP7002_YUV_Y_R_COEF_MSBS 0x4f // 16-bit R’ coefficient MSB for Y MSBS +#define TVP7002_YUV_U_G_COEF_LSBS 0x50 // 16-bit G’ coefficient MSB for U LSBS +#define TVP7002_YUV_U_G_COEF_MSBS 0x51 // 16-bit G’ coefficient MSB for U MSBS +#define TVP7002_YUV_U_B_COEF_LSBS 0x52 // 16-bit B’ coefficient MSB for U LSBS +#define TVP7002_YUV_U_B_COEF_MSBS 0x53 // 16-bit B’ coefficient MSB for U MSBS +#define TVP7002_YUV_U_R_COEF_LSBS 0x54 // 16-bit R’ coefficient MSB for U LSBS +#define TVP7002_YUV_U_R_COEF_MSBS 0x55 // 16-bit R’ coefficient MSB for U MSBS +#define TVP7002_YUV_V_G_COEF_LSBS 0x56 // 16-bit G’ coefficient MSB for V LSBS +#define TVP7002_YUV_V_G_COEF_MSBS 0x57 // 16-bit G’ coefficient MSB for V MSBS +#define TVP7002_YUV_V_B_COEF_LSBS 0x58 // 16-bit B’ coefficient MSB for V LSBS +#define TVP7002_YUV_V_B_COEF_MSBS 0x59 // 16-bit B’ coefficient MSB for V MSBS +#define TVP7002_YUV_V_R_COEF_LSBS 0x5a // 16-bit R’ coefficient MSB for V LSBS +#define TVP7002_YUV_V_R_COEF_MSBS 0x5b // 16-bit R’ coefficient MSB for V MSBS + diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 74f1687..935176b 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -703,6 +703,14 @@ typedef __u64 v4l2_std_id; V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc |\ V4L2_STD_SECAM) +#define V4L2_STD_725_50 (V4L2_STD_PAL |\ + V4L2_STD_PAL_M |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_SECAM) +#define V4L2_STD_825_60 (V4L2_STD_PAL_M |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_SECAM) #define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ V4L2_STD_ATSC_16_VSB) diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index e8272d1..bb7b2a5 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -65,7 +65,8 @@ struct vpfe_route { enum vpfe_subdev_id { VPFE_SUBDEV_TVP5146 = 1, - VPFE_SUBDEV_MT9T031 = 2 + VPFE_SUBDEV_MT9T031 = 2, + VPFE_SUBDEV_TVP7002 = 3 }; struct vpfe_subdev_info { diff --git a/include/media/tvp7002.h b/include/media/tvp7002.h new file mode 100644 index 0000000..0021906 --- /dev/null +++ b/include/media/tvp7002.h @@ -0,0 +1,250 @@ +/* + tvp7002.h - Definitions for TVP7002 + + Copyright (C) 2009 Santiago Nunez-Corrales (santiago.nunez@ridgerun.com) + + 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. +*/ + +#ifndef _TVP7002_H_ +#define _TVP7002_H_ + +/* Includes */ +#include + +/* Definitions */ + +// Boolean values +#define TRUE 1 +#define FALSE 0 + +// VCO Range +#define TVP7002_VCO_RANGE_ULOW 0x00 +#define TVP7002_VCO_RANGE_LOW 0x40 +#define TVP7002_VCO_RANGE_MED 0x80 +#define TVP7002_VCO_RANGE_HIGH 0xC0 + +// Input selection +enum tvp7002_input { + TVP7002_SOGIN_1 = 0x00, + TVP7002_SOGIN_2 = 0x01, + TVP7002_SOGIN_3 = 0x02, + TVP7002_RIN_1 = 0x04, + TVP7002_RIN_2 = 0x05, + TVP7002_RIN_3 = 0x06, + TVP7002_GIN_1 = 0x08, + TVP7002_GIN_2 = 0x09, + TVP7002_GIN_3 = 0x0a, + TVP7002_GIN_4 = 0x0b, + TVP7002_BIN_1 = 0x0c, + TVP7002_BIN_2 = 0x0d, + TVP7002_BIN_3 = 0x0e, + TVP7002_INVALID +}; + +// Sync-On-Green low pass filter select +#define TVP7002_SOG_LPF_025 0x00 // 2.5 MHz +#define TVP7002_SOG_LPF_100 0x01 // 10 MHz +#define TVP7002_SOG_LPF_330 0x02 // 33 MHz +#define TVP7002_SOG_LPF_BYP 0x03 // Bypass + +// Coarse clamp low pass filter select +#define TVP7002_CLP_LPF_048 0x00 // 4.8 MHz +#define TVP7002_CLP_LPF_005 0x01 // 0.5 MHz +#define TVP7002_CLP_LPF_017 0x02 // 1.7 MHz + +// Clock reference select for Sync Processing Block +#define TVP7002_CLK_REF_IN 0x00 +#define TVP7002_CLK_REF_OUT 0x01 + +// VSYNC input select +#define TVP7002_VSYNC_IN_A 0x00 +#define TVP7002_VSYNC_IN_B 0x01 + +// Pixel clock select +#define TVP7002_PIXEL_CLK_EXT 0x00 +#define TVP7002_PIXEL_CLC_HPLL 0x01 + +// HSYNC input select +#define TVP7002_HSYNC_IN_A 0x00 +#define TVP7002_HSYNX_IN_B 0x01 + +// V4L2 CIDs for controls +// +// According to include/media/videodev2.h, control identifiers are tags +// that label proper functions in the driver (i.e. existing functions that +// are unique). V4L2_CID_PRIVATE_BASE defines a set of idetifiers that, +// starting at address 0x08000000 allow definition of driver-specific +// controls. +#define V4L2_CID_VIDEO_MODE (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_COARSE_GAIN_R (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_COARSE_GAIN_G (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_COARSE_GAIN_B (V4L2_CID_PRIVATE_BASE + 4) +#define V4L2_CID_FINE_GAIN_R (V4L2_CID_PRIVATE_BASE + 5) +#define V4L2_CID_FINE_GAIN_G (V4L2_CID_PRIVATE_BASE + 6) +#define V4L2_CID_FINE_GAIN_B (V4L2_CID_PRIVATE_BASE + 7) +#define V4L2_CID_SOG_IN (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_R_IN (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_G_IN (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_B_IN (V4L2_CID_PRIVATE_BASE + 11) +#define V4L2_CID_SOG_LPF (V4L2_CID_PRIVATE_BASE + 12) +#define V4L2_CID_CLAMP_LPF (V4L2_CID_PRIVATE_BASE + 13) +#define V4L2_CID_CLK_IN (V4L2_CID_PRIVATE_BASE + 14) +#define V4L2_CID_VSYNC_IN (V4L2_CID_PRIVATE_BASE + 15) +#define V4L2_CID_PIXEL_CLK_IN (V4L2_CID_PRIVATE_BASE + 16) +#define V4L2_CID_HSYNC_IN (V4L2_CID_PRIVATE_BASE + 17) +#define V4L2_CID_SOG_THRS (V4L2_CID_PRIVATE_BASE + 18) +#define V4L2_CID_B_CLAMP (V4L2_CID_PRIVATE_BASE + 19) +#define V4L2_CID_G_CLAMP (V4L2_CID_PRIVATE_BASE + 20) +#define V4L2_CID_R_CLAMP (V4L2_CID_PRIVATE_BASE + 21) +#define V4L2_CID_CLAMP_OFF_EN (V4L2_CID_PRIVATE_BASE + 22) +#define V4L2_CID_FCTCA (V4L2_CID_PRIVATE_BASE + 23) +#define V4L2_CID_F_CLAMP_GB (V4L2_CID_PRIVATE_BASE + 24) +#define V4L2_CID_F_CLAMP_R (V4L2_CID_PRIVATE_BASE + 25) +#define V4L2_CID_CLAMP_START (V4L2_CID_PRIVATE_BASE + 26) +#define V4L2_CID_CLAMP_W (V4L2_CID_PRIVATE_BASE + 27) +#define V4L2_CID_B_COARSE_OFF (V4L2_CID_PRIVATE_BASE + 28) +#define V4L2_CID_G_COARSE_OFF (V4L2_CID_PRIVATE_BASE + 29) +#define V4L2_CID_R_COARSE_OFF (V4L2_CID_PRIVATE_BASE + 30) +#define V4L2_CID_B_FINE_OFF (V4L2_CID_PRIVATE_BASE + 31) +#define V4L2_CID_G_FINE_OFF (V4L2_CID_PRIVATE_BASE + 32) +#define V4L2_CID_R_FINE_OFF (V4L2_CID_PRIVATE_BASE + 33) +#define V4L2_CID_ALC_EN (V4L2_CID_PRIVATE_BASE + 34) +#define V4L2_CID_ALC_PLACEMENT (V4L2_CID_PRIVATE_BASE + 35) +#define V4L2_CID_ALC_FILTER_VERT_CF (V4L2_CID_PRIVATE_BASE + 36) +#define V4L2_CID_ALC_FILTER_HORZ_CF (V4L2_CID_PRIVATE_BASE + 37) +#define V4L2_CID_CLAMP_ALC_PULSE_RF (V4L2_CID_PRIVATE_BASE + 38) +#define V4L2_CID_OUT_CODE_RANGE (V4L2_CID_PRIVATE_BASE + 39) +#define V4L2_CID_OUT_CBCR_ORDER (V4L2_CID_PRIVATE_BASE + 40) +#define V4L2_CID_OUT_422_444 (V4L2_CID_PRIVATE_BASE + 41) +#define V4L2_CID_OUT_EMB_SYNC_EN (V4L2_CID_PRIVATE_BASE + 42) +#define V4L2_CID_SYNC_HSPO (V4L2_CID_PRIVATE_BASE + 43) +#define V4L2_CID_SYNC_HSIP (V4L2_CID_PRIVATE_BASE + 44) +#define V4L2_CID_SYNC_HSOP (V4L2_CID_PRIVATE_BASE + 45) +#define V4L2_CID_SYNC_AHSO (V4L2_CID_PRIVATE_BASE + 46) +#define V4L2_CID_SYNC_AHSS (V4L2_CID_PRIVATE_BASE + 47) +#define V4L2_CID_SYNC_VSOP (V4L2_CID_PRIVATE_BASE + 48) +#define V4L2_CID_SYNC_AVSO (V4L2_CID_PRIVATE_BASE + 49) +#define V4L2_CID_SYNC_AVSS (V4L2_CID_PRIVATE_BASE + 50) +#define V4L2_CID_SEEK_MODE_OVRD (V4L2_CID_PRIVATE_BASE + 51) +#define V4L2_CID_PWR_FCPD (V4L2_CID_PRIVATE_BASE + 52) +#define V4L2_CID_PWR_SOG_PWDN (V4L2_CID_PRIVATE_BASE + 53) +#define V4L2_CID_PWR_SLICER_PWDN (V4L2_CID_PRIVATE_BASE + 54) +#define V4L2_CID_PWR_REF_PWDN (V4L2_CID_PRIVATE_BASE + 55) +#define V4L2_CID_PWR_CURRENT_PWDN (V4L2_CID_PRIVATE_BASE + 56) +#define V4L2_CID_PWR_ADC_B_PWDN (V4L2_CID_PRIVATE_BASE + 57) +#define V4L2_CID_PWR_ADC_G_PWDN (V4L2_CID_PRIVATE_BASE + 58) +#define V4L2_CID_PWR_ADC_R_PWDN (V4L2_CID_PRIVATE_BASE + 59) + +/* Resolution identifiers + * + * Standard_Resolution_FrameRate[_PixelRate] + */ +#define V4L2_STD_TVP7002_BASE_STD 0x04000000 +#define TVP7002_VGA_640_480_60 ((v4l2_std_id)V4L2_STD_TVP7002_BASE_STD) +#define TVP7002_VGA_640_480_73 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 1)) +#define TVP7002_VGA_640_480_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 2)) +#define TVP7002_VGA_640_480_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 3)) +#define TVP7002_SVGA_800_600_56 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 4)) +#define TVP7002_SVGA_800_600_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 5)) +#define TVP7002_SVGA_800_600_72 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 6)) +#define TVP7002_SVGA_800_600_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 7)) +#define TVP7002_SVGA_800_600_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 8)) +#define TVP7002_XGA_1024_768_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 9)) +#define TVP7002_XGA_1024_768_70 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 10)) +#define TVP7002_XGA_1024_768_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 11)) +#define TVP7002_XGA_1024_768_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 12)) +#define TVP7002_WXGA1_1280_768_60_L ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 13)) +#define TVP7002_WXGA1_1280_768_60_H ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 14)) +#define TVP7002_WXGA1_1280_768_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 15)) +#define TVP7002_WXGA1_1280_768_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 16)) +#define TVP7002_SXGA_1280_1024_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 17)) +#define TVP7002_SXGA_1280_1024_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 18)) +#define TVP7002_SXGA_1280_1024_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 19)) +#define TVP7002_SXGAPLUS_1400_1050_60_L ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 20)) +#define TVP7002_SXGAPLUS_1400_1050_60_H ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 21)) +#define TVP7002_SXGAPLUS_1400_1050_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 22)) +#define TVP7002_WXGA2_1440_900_60_L ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 23)) +#define TVP7002_WXGA2_1440_900_60_H ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 24)) +#define TVP7002_WXGA2_1440_900_75 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 25)) +#define TVP7002_WXGA2_1440_900_85 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 26)) +#define TVP7002_UXGA_1600_1200_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 27)) +#define TVP7002_VIDEOI_720_480_30 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 28)) +#define TVP7002_VIDEOI_720_576_25 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 29)) +#define TVP7002_VIDEOP_720_480_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 30)) +#define TVP7002_VIDEOP_720_576_50 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 31)) +#define TVP7002_VIDEOP_1280_720_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 32)) +#define TVP7002_VIDEOP_1280_720_50 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 33)) +#define TVP7002_VIDEOI_1920_1080_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 34)) +#define TVP7002_VIDEOI_1920_1080_50 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 35)) +#define TVP7002_VIDEOP_1920_1080_60 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 36)) +#define TVP7002_VIDEOP_1920_1080_50 ((v4l2_std_id)(V4L2_STD_TVP7002_BASE_STD + 37)) + +/* Struct for handling resolutions and associate register values */ + +struct tvp7002_resol { + int id; // ID + int hres; // Horizontal resolution + int vres; // Vertical resolution + int frate; // Frame rate + int lrate; // Line rate + int prate; // Pixel rate + unsigned char reg01; // Value for register 0x01h + unsigned char reg02; // Value for register 0x02h + unsigned char reg03; // Value for register 0x03h + unsigned char reg04; // Value for register 0x04h + int available; // Is this resolution available for this platform? +}; + +/* Struct for handling register values */ +struct i2c_reg_value { + unsigned char reg; + unsigned char value; +}; + +/* */ +struct tvp7002_platform_data { + /* Interface control params */ + bool clk_polarity; + bool hs_polarity; + bool vs_polarity; +}; + +/* Prototypes */ +static int tvp7002_read(struct v4l2_subdev *, unsigned char); +static int tvp7002_write(struct v4l2_subdev *, unsigned char, unsigned char); +static void dump_reg_range(struct v4l2_subdev *, char *, u8, const u8, int); +static int tvp7002_log_status(struct v4l2_subdev *); +static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *); +static int tvp7002_write_inittab(struct v4l2_subdev *, const struct i2c_reg_value *); +static int tvp7002_set_video_mode(struct v4l2_subdev *, int); +static int tvp7002_get_video_mode(struct v4l2_subdev *); +static int tvp7002_s_std(struct v4l2_subdev *sd, v4l2_std_id std); +static int tvp7002_querystd(struct v4l2_subdev *, v4l2_std_id *); +static int tvp7002_g_chip_ident(struct v4l2_subdev *, struct v4l2_dbg_chip_ident *); +static int tvp7002_set_std_format(struct v4l2_subdev *, unsigned int); +static int tvp7002_g_ctrl(struct v4l2_subdev *, struct v4l2_control *); +static int tvp7002_s_ctrl(struct v4l2_subdev *, struct v4l2_control *); +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int tvp7002_g_register(struct v4l2_subdev *, struct v4l2_dbg_register *); +static int tvp7002_s_register(struct v4l2_subdev *, struct v4l2_dbg_register *); +#endif +static int tvp7002_queryctrl(struct v4l2_subdev *, struct v4l2_queryctrl *); +static int tvp7002_reset(struct v4l2_subdev *, u32); +static int tvp7002_probe(struct i2c_client *, const struct i2c_device_id *); + +static int tvp7002_remove(struct i2c_client *); + +#endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 94e908c..b8c86d9 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -129,6 +129,9 @@ enum { V4L2_IDENT_SAA6752HS = 6752, V4L2_IDENT_SAA6752HS_AC3 = 6753, + /* module tvp7002: just ident 7002 */ + V4L2_IDENT_TVP7002 = 7002, + /* module adv7170: just ident 7170 */ V4L2_IDENT_ADV7170 = 7170,