Message ID | 1250894224-16981-1-git-send-email-santiago.nunez@ridgerun.com (mailing list archive) |
---|---|
State | Rejected |
Headers | show |
Santiago, Thanks for sending the patch for review. I was surprised to see the hw configuration part of the code is different from LSP 2.10. Having a entirely new code adds to the risk in development. Any reason, why you have chosen not to re-use the code? Here are the additional comments I have on the patch.. - So many controls added. So what are your requirement w.r.t to control from user space? Whatever controls used should be standard ones picked from the v4l2 spec or that we could add to v4l2 spec. Many of the controls that you have implemented should be left as defaults or should be exported to user space as a configuration ioctl if require configuration from user space. Only control that make sense to me is the analog and digital gain/offsets and clamp. Also these controls may not be available for all types of input. For example since chip support capture from a vesa source, it may be supporting gain/offsets in RGB color space, but for TV input, the data is in YPbPr color space. Please investigate this. Also check videodev2.h in latest open source kernel to investigate if there are control ids available to implement these or need to add new ones. - So many modes available. But only 2 are added to vpfe capture. What are the requirements here? If you need VESA timings and video (Analog & Digital) timings, then it make sense to support all modes that are supported by the chip. In that case you need to add the timing for this in the vpfe capture driver as well. Also input selection from all these sources should be possible. But at least from DM365 and DM6467 perspectives, I would like to see support for 720p 50/60, 1080i 50/60 & 1080p 50/60 for HDTV and also 480p/576p for SDTV. Please clarify. - The comments are using // which are not allowed. Please refer the coding style for open source development. - Please split this into multiple patches and add description to each. So when you are ready to submit it to community, it will be a lot easier. See additional comments inline below with [MK] prefix. Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 email: m-karicheri2@ti.com > #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 >+}; [MK] I don't see it being used in your driver TVP7002 driver. In probe() these values are to be read and used for setting polarities as needed. This will allow for customization in individual boards. So also add fid polarity and clock polarity which are also configurable in the chip. >+ > /* 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) [MK]You have used many modes in your driver. Why only these used here. What is V4L2_STD_725_50 & V4L2_STD_825_60? Whatever modes required as per the requirement should be added here so that vpfe capture will be able to support it while doing s_std(). >+/* 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, >+ }, [MK] OUTPUT_10BIT_422_EMBEDDED_SYNC is not correct for TVP7002. It should be 20bit 422. But both of these are not required in my opinion as given below. This is part of the interface configuration. >+}; >+ [MK]If your requirement is to support multiple input sources:- to capture from PC VESA source, Composite source or component source etc, then it make sense to create multiple input selection logic. In that case multiple inputs to be defined and corresponding selector values are required in tvp7002 routes. If your driver is just supporting component input to capture 480p/576p and HD standards, then you may not require to add routes here and need not set can_route below. I see only requirement to capture from TV source at this time. Is this a requirement from Ridgerun to support VESA ? > 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}, > }; [MK]Why V4L2_STD_725_50 & V4L2_STD_825_60? it should be V4L2_STD_720P_50, V4L2_STD_720P_60, V4L2_STD_1080I_50 and so forth. > > /* 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 >+ */ [MK] Are you putting proper GPL header here? If re-using TI code, then Texas Instruments should be in the header, right? >+ >+#include <linux/i2c.h> >+#include <linux/videodev2.h> >+#include <linux/delay.h> >+#include <media/v4l2-device.h> >+#include <media/tvp7002.h> >+#include <media/v4l2-i2c-drv.h> >+#include <media/v4l2-chip-ident.h> >+#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, [MK] Why this non-standard frame rate? Please check VESA timings and use right frame rate for all supported standards. >+ .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, [MK]change this to NTSC standard as in tvp514x.c >+ .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, [MK] change this to PAL standard as in tvp514x.c >+ .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, >+ }, >+}; [MK] I think you need to Keep 3 set of timings. One for Analog TV standard, like NTSC, PAL as in TVP514x and another for VESA timings, and third for Digital TV timings. That way at least the analog TV standards handling code will not change in future since that is well standardized. Digital video and VESA timings are to be changed using the new IOCTL being proposed by Hans. So if that accepted in some form, only that code needs to be modified. >+ >+/* 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, >+ } >+}; [MK] See my earlier comment. Only keep Gain/Offset/Clamp for control. Rest of them use default to begin with unless you have specific requirement to support. >+ >+/** 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, >+}; [MK] please add a function to start streaming s_stream. See tvp514x.c for example. Also make sense to add a g_fmt() >+ >+static const struct v4l2_subdev_ops tvp7002_ops = { >+ .core = &tvp7002_core_ops, >+ .video = &tvp7002_video_ops, >+}; >+ >+/*** Functions ***/ [MK] /**** xxx ****/ shouldn't be used. Use as per coding style. >+ >+/** 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); >+ [MK] Why can't use i2c_smbus_read_byte_data() as in tvp514x? Why send and receive(). This always create problems when multiple tasks use the driver, when while one send a command, get swapped and another use i2c to send/receive commands. It appears that you have used TVP5150 code as reference. There is a kernel oops discussion relating to tvp5150 in the linux-media list and it is attributed to this , I think. >+ 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))){ [MK] Similar comment as above >+ v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be >2)\n", rc); >+ return -1; [MK] return proper error code >+ } >+ >+ 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 */ [MK] Please add proper function header as per Kernel coding style for all functions. >+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; [MK] you are indexing into the tvp7002_resolutions array with out checking for it's range. Also return -EINVAL if not supported instead of -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); [MK] No prink please, use v4l2_dbg() >+ /* 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 [MK] No // allowed for comment. Please correct all instances >+ 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); >+ } >+ [MK]. Looks like you are handling SD/HD/VESA modes differently. So defining separate table for the timing as suggested earlier make sense. >+ 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); [MK] What if there are errors while reading these registers? It should be handled gracefully. >+ >+ switch(reg01){ >+ case 0x32: >+ return TVP7002_VGA_640_480_60; [MK] Just set the value in a temporary variable and return at the end. >+ 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; [MK] Default case?? Also why there is no return error if none of the value match. >+ } >+} >+ >+/* 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); [MK] Why not just do return tvp7002_set_video_mode(sd, vmd); In your case it always return success even if there is a failure. >+ >+ return 0; >+} >+ >+static int tvp7002_querystd(struct v4l2_subdev *sd, v4l2_std_id *std){ >+ (*std) = tvp7002_get_video_mode(sd); >+ [MK] Please add the querystd() handling from LSP210. >+ 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; [MK] return at the end. Also handle error from tvp7002_read(). >+ 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; >+ } >+ Make sense to add a common function to check if the id is in the list of supported IDs and call it from s_ctrl(), g_ctrl() & queryctrl() to validate. >+ 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; >+} >+ [MK] Both of the above should be under #ifdef CONFIG_VIDEO_ADV_DEBUG >+/* 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) { [MK] suggest re-use a common function to validate control ID (as commented before) >+ 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 >+ */ [MK] Use proper copy rights, GPL etc. >+ >+/* 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âEUR(tm) coefficient MSB >for Y LSBS >+#define TVP7002_YUV_Y_G_COEF_MSBS 0x4b // 16-bit GâEUR(tm) coefficient >MSB for Y MSBS >+#define TVP7002_YUV_Y_B_COEF_LSBS 0x4c // 16-bit BâEUR(tm) coefficient >MSB for Y LSBS >+#define TVP7002_YUV_Y_B_COEF_MSBS 0x4d // 16-bit BâEUR(tm) coefficient >MSB for Y MSBS >+#define TVP7002_YUV_Y_R_COEF_LSBS 0x4e // 16-bit RâEUR(tm) coefficient >MSB for Y LSBS >+#define TVP7002_YUV_Y_R_COEF_MSBS 0x4f // 16-bit RâEUR(tm) coefficient >MSB for Y MSBS >+#define TVP7002_YUV_U_G_COEF_LSBS 0x50 // 16-bit GâEUR(tm) coefficient >MSB for U LSBS >+#define TVP7002_YUV_U_G_COEF_MSBS 0x51 // 16-bit GâEUR(tm) coefficient >MSB for U MSBS >+#define TVP7002_YUV_U_B_COEF_LSBS 0x52 // 16-bit BâEUR(tm) coefficient >MSB for U LSBS >+#define TVP7002_YUV_U_B_COEF_MSBS 0x53 // 16-bit BâEUR(tm) coefficient >MSB for U MSBS >+#define TVP7002_YUV_U_R_COEF_LSBS 0x54 // 16-bit RâEUR(tm) coefficient >MSB for U LSBS >+#define TVP7002_YUV_U_R_COEF_MSBS 0x55 // 16-bit RâEUR(tm) coefficient >MSB for U MSBS >+#define TVP7002_YUV_V_G_COEF_LSBS 0x56 // 16-bit GâEUR(tm) coefficient >MSB for V LSBS >+#define TVP7002_YUV_V_G_COEF_MSBS 0x57 // 16-bit GâEUR(tm) coefficient >MSB for V MSBS >+#define TVP7002_YUV_V_B_COEF_LSBS 0x58 // 16-bit BâEUR(tm) coefficient >MSB for V LSBS >+#define TVP7002_YUV_V_B_COEF_MSBS 0x59 // 16-bit BâEUR(tm) coefficient >MSB for V MSBS >+#define TVP7002_YUV_V_R_COEF_LSBS 0x5a // 16-bit RâEUR(tm) coefficient >MSB for V LSBS >+#define TVP7002_YUV_V_R_COEF_MSBS 0x5b // 16-bit RâEUR(tm) 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) [MK] What are all these new Standards you are trying to define here? > #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. >+*/ >+ [MK] Add proper copy rights based on my earlier comments. >+#ifndef _TVP7002_H_ >+#define _TVP7002_H_ >+ >+/* Includes */ >+#include <linux/videodev2.h> >+ >+/* 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 [MK] Use of V4L2_CID_PRIVATE_BASE is now allowed. Please participate with community to add the control properly. You have to use existing control class or add new and implement it using extended controls. >+// 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 [MK] Shouldn't we define bit masks here ? >+#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? [MK] What you mean by this? >+}; >+ >+/* 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; >+}; You should use these values in the code. Also add fid polarity >+ >+/* Prototypes */ [MK] Prototypes are not required if the code is arranged properly. Please re-arrange the code to remove these proptypes. >+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, > >-- >1.6.0.4 >
Murali, Thanks for promptly reviewing the code. Please see inline comments. Karicheri, Muralidharan wrote: > Santiago, > > Thanks for sending the patch for review. > > I was surprised to see the hw configuration part of the code is different from LSP 2.10. Having a entirely new code adds to the risk in development. > Any reason, why you have chosen not to re-use the code? > The reason for not reusing the code was based upon the amount of changes in the v4l2 interface in TVP7002 between 2.6.18 and 2.6.31, which made some changes unnatural with respect to functionality and semantics. I also agree this was a risky approach though. > Here are the additional comments I have on the patch.. > > - So many controls added. So what are your requirement w.r.t to control from user space? Whatever controls used should be standard ones picked from the v4l2 spec or that we could add to v4l2 spec. Many of the controls that you have implemented should be left as defaults or should be exported to user space as a configuration ioctl if require configuration from user space. Only control that make sense to me is the analog and digital gain/offsets and clamp. Also these controls may not be available for all types of input. For example since chip support capture from a vesa source, it may be supporting gain/offsets in RGB color space, but for TV input, the data is in YPbPr color space. Please investigate this. Also check videodev2.h in latest open source kernel to investigate if there are control ids available to implement these or need to add new ones. > I will reduce the amount of controls to standard ones in V4L2 and work with the community for the new ones. > - So many modes available. But only 2 are added to vpfe capture. What are the requirements here? If you need VESA timings and video (Analog & Digital) timings, then it make sense to support all modes that are supported by the chip. In that case you need to add the timing for this in the vpfe capture driver as well. Also input selection from all these sources should be possible. But at least from DM365 and DM6467 perspectives, I would like to see support for 720p 50/60, 1080i 50/60 & 1080p 50/60 for HDTV and also 480p/576p for SDTV. Please clarify. > > For the specific case of modes, the main goal was to match as closely as possible the tvp7002 specification on modes it provides but I'd like to hear from the expectations of the community on which modes are prioritary. I will add specific support for those above mentioned. > - The comments are using // which are not allowed. Please refer the coding style for open source development. > > - Please split this into multiple patches and add description to each. So > when you are ready to submit it to community, it will be a lot easier. > > Understood. Read relevant open source docs and working on matching the standard. > See additional comments inline below with [MK] prefix. > > Murali Karicheri > Software Design Engineer > Texas Instruments Inc. > Germantown, MD 20874 > email: m-karicheri2@ti.com > > > >> #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 >> +}; >> > > > [MK] I don't see it being used in your driver TVP7002 driver. In probe() these values are to be read and used for setting polarities as needed. This will allow for customization in individual boards. So also add fid polarity and clock polarity which are also configurable in the chip. > It is required by vpfe_capture for setting up polarities. Will add fid and clocl polarity. >> + >> /* 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) >> > > > [MK]You have used many modes in your driver. Why only these used here. What is V4L2_STD_725_50 & V4L2_STD_825_60? Whatever modes required as per the requirement should be added here so that vpfe capture will be able to support it while doing s_std(). > I will add the other modes as suggested. In the case of the mode definitions, my impression was that there existed a convention since the other modes (V4L2_STD_525_60 and V4L2_STD_625_50) provide no immediate information upon their names on resolution, only frequency. Should they be redefined according to these criteria? >> +/* 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, >> + }, >> > [MK] OUTPUT_10BIT_422_EMBEDDED_SYNC is not correct for TVP7002. It should be > 20bit 422. But both of these are not required in my opinion as given below. > This is part of the interface configuration. > Ok. >> +}; >> + >> > > [MK]If your requirement is to support multiple input sources:- to capture from PC VESA source, Composite source or component source etc, then it make sense to create multiple input selection logic. In that case multiple inputs to be defined and corresponding selector values are required in tvp7002 routes. If your driver is just supporting component input to capture 480p/576p and HD standards, then you may not require to add routes here and need not set can_route below. I see only requirement to capture from TV source at this time. Is this a requirement from Ridgerun to support VESA ? > Ok. Changing to support SD/HD standards. > >> 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}, >> }; >> > > > [MK]Why V4L2_STD_725_50 & V4L2_STD_825_60? it should be V4L2_STD_720P_50, V4L2_STD_720P_60, V4L2_STD_1080I_50 and so forth. > See comment above regarding naming. > >> /* 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 >> + */ >> >> [MK] Are you putting proper GPL header here? If re-using TI code, then Texas Instruments should be in the header, right? >> >> +#include <linux/i2c.h> >> +#include <linux/videodev2.h> >> +#include <linux/delay.h> >> +#include <media/v4l2-device.h> >> +#include <media/tvp7002.h> >> +#include <media/v4l2-i2c-drv.h> >> +#include <media/v4l2-chip-ident.h> >> +#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, >> > [MK] Why this non-standard frame rate? Please check VESA timings and use right frame rate for all supported standards. > These are timings specified by the tvp7002 datasheet, pages 15 and 16. I will check with standard rates. >> + .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, >> > [MK]change this to NTSC standard as in tvp514x.c > Ok. >> + .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, >> > [MK] change this to PAL standard as in tvp514x.c > Ok. >> + .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, >> + }, >> +}; >> > [MK] I think you need to Keep 3 set of timings. One for Analog TV standard, like NTSC, PAL as in TVP514x and another for VESA timings, and third for Digital TV timings. That way at least the analog TV standards handling code will not change in future since that is well standardized. Digital video and VESA timings are to be changed using the new IOCTL being proposed by Hans. So if that accepted in some form, only that code needs to be modified. > Ok. >> + >> +/* 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, >> + } >> +}; >> > [MK] See my earlier comment. Only keep Gain/Offset/Clamp for control. Rest of them use default to begin with unless you have specific requirement to support. > Ok. >> + >> +/** 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, >> +}; >> > [MK] please add a function to start streaming s_stream. See tvp514x.c for example. Also make sense to add a g_fmt() > > Ok. >> + >> +static const struct v4l2_subdev_ops tvp7002_ops = { >> + .core = &tvp7002_core_ops, >> + .video = &tvp7002_video_ops, >> +}; >> + >> +/*** Functions ***/ >> > > [MK] /**** xxx ****/ shouldn't be used. Use as per coding style. > > KO. >> + >> +/** 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); >> + >> > [MK] Why can't use i2c_smbus_read_byte_data() as in tvp514x? Why send and receive(). This always create problems when multiple tasks use the driver, when while one send a command, get swapped and another use i2c to send/receive commands. It appears that you have used TVP5150 code as reference. There is a kernel oops discussion relating to tvp5150 in the linux-media list and it is attributed to this , I think. > > Yes, I used TVP5150 as reference (not TI LSP code as you noted in the first comments). Hmm that is a good point for reentrant code using the driver. Will change accordingly. >> + 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))){ >> > [MK] Similar comment as above > Ok. >> + v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be >> 2)\n", rc); >> + return -1; >> > > > [MK] return proper error code > Ok. > >> + } >> + >> + 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 */ >> > > > [MK] Please add proper function header as per Kernel coding style > for all functions. > > Ok. >> +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; >> > [MK] you are indexing into the tvp7002_resolutions array with out checking > for it's range. Also return -EINVAL if not supported instead of -1 > > Ok. >> + } >> + >> + /* 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); >> > > > [MK] No prink please, use v4l2_dbg() > > Ok. >> + /* 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 >> > > > [MK] No // allowed for comment. Please correct all instances > Ok. > >> + 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); >> + } >> + >> > [MK]. Looks like you are handling SD/HD/VESA modes differently. So defining separate table for the timing as suggested earlier make sense. > > Ok. >> + 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); >> > [MK] What if there are errors while reading these registers? It should > be handled gracefully. > Ok. >> + >> + switch(reg01){ >> + case 0x32: >> + return TVP7002_VGA_640_480_60; >> > [MK] Just set the value in a temporary variable and return at the end. > > Ok. >> + 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; >> > [MK] Default case?? Also why there is no return error if none > of the value match. > Adding default case and error handling. >> + } >> +} >> + >> +/* 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); >> > [MK] Why not just do return tvp7002_set_video_mode(sd, vmd); In your case it always return success even if there is a failure. > > Ok. >> + >> + return 0; >> +} >> + >> +static int tvp7002_querystd(struct v4l2_subdev *sd, v4l2_std_id *std){ >> + (*std) = tvp7002_get_video_mode(sd); >> + >> > > > [MK] Please add the querystd() handling from LSP210. > > Ok. >> + 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; >> > > [MK] return at the end. Also handle error from tvp7002_read(). > Ok. >> + 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; >> + } >> + >> > Make sense to add a common function to check if the id is in the list of supported IDs and call it from s_ctrl(), g_ctrl() & queryctrl() to validate. > Good observation. Changing accordingly. > >> + 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; >> +} >> + >> > [MK] Both of the above should be under #ifdef CONFIG_VIDEO_ADV_DEBUG > > Ok. >> +/* 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) { >> > > > [MK] suggest re-use a common function to validate control ID (as commented before) > > Ok. >> + 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 >> + */ >> > [MK] Use proper copy rights, GPL etc. > Ok. >> + >> +/* 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âEUR(tm) coefficient MSB >> for Y LSBS >> +#define TVP7002_YUV_Y_G_COEF_MSBS 0x4b // 16-bit GâEUR(tm) coefficient >> MSB for Y MSBS >> +#define TVP7002_YUV_Y_B_COEF_LSBS 0x4c // 16-bit BâEUR(tm) coefficient >> MSB for Y LSBS >> +#define TVP7002_YUV_Y_B_COEF_MSBS 0x4d // 16-bit BâEUR(tm) coefficient >> MSB for Y MSBS >> +#define TVP7002_YUV_Y_R_COEF_LSBS 0x4e // 16-bit RâEUR(tm) coefficient >> MSB for Y LSBS >> +#define TVP7002_YUV_Y_R_COEF_MSBS 0x4f // 16-bit RâEUR(tm) coefficient >> MSB for Y MSBS >> +#define TVP7002_YUV_U_G_COEF_LSBS 0x50 // 16-bit GâEUR(tm) coefficient >> MSB for U LSBS >> +#define TVP7002_YUV_U_G_COEF_MSBS 0x51 // 16-bit GâEUR(tm) coefficient >> MSB for U MSBS >> +#define TVP7002_YUV_U_B_COEF_LSBS 0x52 // 16-bit BâEUR(tm) coefficient >> MSB for U LSBS >> +#define TVP7002_YUV_U_B_COEF_MSBS 0x53 // 16-bit BâEUR(tm) coefficient >> MSB for U MSBS >> +#define TVP7002_YUV_U_R_COEF_LSBS 0x54 // 16-bit RâEUR(tm) coefficient >> MSB for U LSBS >> +#define TVP7002_YUV_U_R_COEF_MSBS 0x55 // 16-bit RâEUR(tm) coefficient >> MSB for U MSBS >> +#define TVP7002_YUV_V_G_COEF_LSBS 0x56 // 16-bit GâEUR(tm) coefficient >> MSB for V LSBS >> +#define TVP7002_YUV_V_G_COEF_MSBS 0x57 // 16-bit GâEUR(tm) coefficient >> MSB for V MSBS >> +#define TVP7002_YUV_V_B_COEF_LSBS 0x58 // 16-bit BâEUR(tm) coefficient >> MSB for V LSBS >> +#define TVP7002_YUV_V_B_COEF_MSBS 0x59 // 16-bit BâEUR(tm) coefficient >> MSB for V MSBS >> +#define TVP7002_YUV_V_R_COEF_LSBS 0x5a // 16-bit RâEUR(tm) coefficient >> MSB for V LSBS >> +#define TVP7002_YUV_V_R_COEF_MSBS 0x5b // 16-bit RâEUR(tm) 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) >> > > > [MK] What are all these new Standards you are trying to define here? > > >> #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. >> +*/ >> + >> > [MK] Add proper copy rights based on my earlier comments. > Ok. > >> +#ifndef _TVP7002_H_ >> +#define _TVP7002_H_ >> + >> +/* Includes */ >> +#include <linux/videodev2.h> >> + >> +/* 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 >> > [MK] Use of V4L2_CID_PRIVATE_BASE is now allowed. Please participate with > community to add the control properly. You have to use existing control class or add new and implement it using extended controls. > Ok. > >> +// 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 >> > > [MK] Shouldn't we define bit masks here ? > Yes, adding that > >> +#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? >> > [MK] What you mean by this? > I meant a flag in case the mode was not enabled in this platform dynamically, but seems to be of no use. Removing it. >> +}; >> + >> +/* 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; >> +}; >> > You should use these values in the code. Also add fid polarity > Ok. >> + >> +/* Prototypes */ >> > > > [MK] Prototypes are not required if the code is arranged properly. Please re-arrange the code to remove these proptypes. > Ok. > >> +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, >> >> -- >> 1.6.0.4 >> >> > >
Santiago, <Snip> >> - So many modes available. But only 2 are added to vpfe capture. What are >the requirements here? If you need VESA timings and video (Analog & >Digital) timings, then it make sense to support all modes that are >supported by the chip. In that case you need to add the timing for this in >the vpfe capture driver as well. Also input selection from all these >sources should be possible. But at least from DM365 and DM6467 perspectives, >I would like to see support for 720p 50/60, 1080i 50/60 & 1080p 50/60 for >HDTV and also 480p/576p for SDTV. Please clarify. >> >> >For the specific case of modes, the main goal was to match as closely as >possible the tvp7002 specification on modes it provides but I'd like to >hear from the expectations of the community on which modes are >prioritary. I will add specific support for those above mentioned. [MK] Once this is submitted to community anyone can add modes as needed. So I suggest you focus on the above modes only for the initial patch you are sending to community. >>> >>> +// According to TI's tvp7002 datasheet >>> +static struct tvp7002_platform_data tvp7002_pdata = { >>> + .clk_polarity = 0, >>> + .hs_polarity = 1, >>> + .vs_polarity = 1 >>> +}; >>> >> >> >> [MK] I don't see it being used in your driver TVP7002 driver. In probe() >these values are to be read and used for setting polarities as needed. This >will allow for customization in individual boards. So also add fid polarity >and clock polarity which are also configurable in the chip. >> >It is required by vpfe_capture for setting up polarities. Will add fid >and clocl polarity. [MK] vpfe capture will not consume this, but the sub device does. It gets it as platform data. So you need to set polarity in the sub device based on this. Checkout tvp514x for usage. >> [MK]You have used many modes in your driver. Why only these used here. >What is V4L2_STD_725_50 & V4L2_STD_825_60? Whatever modes required as per >the requirement should be added here so that vpfe capture will be able to >support it while doing s_std(). >> >I will add the other modes as suggested. In the case of the mode >definitions, my impression was that there existed a convention since the >other modes (V4L2_STD_525_60 and V4L2_STD_625_50) provide no immediate >information upon their names on resolution, only frequency. Should they >be redefined according to these criteria? [MK] Please focus on the list of modes I have provided. We can always add other modes as needed later. For TI/Ridgerun requirement, the above mode list will suffice (unless Ridgerun has additional requirement that I am not aware of). BTW, I have added a patch for the standards definition for drivers internal development. Sneha will be sending you this patch. This defines all modes for internal development and will be called include/media/davinci/videohd.h. Include this file in the source code. Note that this code can't be submitted to upstream.
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 <mach/nand.h> #include <linux/videodev2.h> #include <media/tvp514x.h> +#include <media/tvp7002.h> 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 <linux/i2c.h> +#include <linux/videodev2.h> +#include <linux/delay.h> +#include <media/v4l2-device.h> +#include <media/tvp7002.h> +#include <media/v4l2-i2c-drv.h> +#include <media/v4l2-chip-ident.h> +#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 <linux/videodev2.h> + +/* 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,
From: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com> --- 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