Santiago, you are missing a tvp7002_init() that calls i2c_add_driver(). Similarly i2c_del_driver(). See tvp514x.c or adv7353.c for examples... Also read the polarities from platform_data in probe(). I had mentioned the second comment during earlier review.
Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 new phone: 301-407-9583 Old Phone : 301-515-3736 (will be deprecated) email: m-kariche...@ti.com >-----Original Message----- >From: santiago.nu...@ridgerun.com [mailto:santiago.nu...@ridgerun.com] >Sent: Tuesday, September 01, 2009 6:55 PM >To: Karicheri, Muralidharan >Cc: davinci-linux-open-source@linux.davincidsp.com; >todd.fisc...@ridgerun.com; diego.do...@ridgerun.com; >clark.bec...@ridgerun.com; Narnakaje, Snehaprabha; Santiago Nunez-Corrales >Subject: [PATCH 5/6 v3] Updated TVP7002 driver for DM365 > >From: Santiago Nunez-Corrales <santiago.nu...@ridgerun.com> > >This patch provides the implementation of the TVP7002 decoder >driver for DM365. Implemented revisions by Vaibhav Hiremath >and Hans Verkuil. Removed most of controls, cleared up logic, >cleaned up code. > >Signed-off-by: Santiago Nunez-Corrales <santiago.nu...@ridgerun.com> >--- > drivers/media/video/tvp7002.c | 1493 >+++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 1493 insertions(+), 0 deletions(-) > create mode 100644 drivers/media/video/tvp7002.c > >diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c >new file mode 100644 >index 0000000..e8cd77e >--- /dev/null >+++ b/drivers/media/video/tvp7002.c >@@ -0,0 +1,1493 @@ >+/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics >+ * Digitizer with Horizontal PLL registers >+ * >+ * Copyright (C) 2009 Texas Instruments Inc >+ * Author: Santiago Nunez-Corrales <santiago.nu...@ridgerun.com> >+ * >+ * This code is partially based upon the TVP5150 driver >+ * written by Mauro Carvalho Chehab (mche...@infradead.org) >+ * and the TVP514x driver written by Vaibhav Hiremath <hvaib...@ti.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. >+ */ >+ >+#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 <media/davinci/videohd.h> >+#include "tvp7002_reg.h" >+ >+MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver"); >+MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nu...@ridgerun.com>"); >+MODULE_LICENSE("GPL"); >+ >+/* I2C retry attempts */ >+#define I2C_RETRY_COUNT (5) >+ >+/* Debugging information */ >+ >+static int debug; >+module_param(debug, int, 0); >+MODULE_PARM_DESC(debug, "Debug level (0-2)"); >+ >+/* Reference to tvp7002_platform_data */ >+extern struct tvp7002_platform_data tvp7002_pdata; >+ >+/* Struct for handling resolutions and associate register values */ >+struct tvp7002_resol { >+ v4l2_std_id id; >+ int hres; >+ int vres; >+ int frate; >+ int lrate; >+ int prate; >+ u8 reg01; >+ u8 reg02; >+ u8 reg03; >+ u8 reg04; >+}; >+ >+/* Struct for handling register values */ >+struct i2c_reg_value { >+ u8 reg; >+ u8 value; >+}; >+ >+/* Register default values (according to tvp7002 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 }, >+ { 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 }, >+ { 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 }, >+ { 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 }, >+ { 0x5c, 0x00 } /* end of registers */ >+}; >+ >+/* Available resolutions */ >+static struct tvp7002_resol tvp7002_resolutions[] = { >+ { >+ .id = V4L2_STD_525I_60, >+ .hres = 720, >+ .vres = 480, >+ .frate = 30, >+ .lrate = 15, >+ .prate = 14, >+ .reg01 = 0x35, >+ .reg02 = 0xa0, >+ .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_625I_50, >+ .hres = 720, >+ .vres = 576, >+ .frate = 25, >+ .lrate = 16, >+ .prate = 14, >+ .reg01 = 0x36, >+ .reg02 = 0x00, >+ .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_525P_60, >+ .hres = 720, >+ .vres = 480, >+ .frate = 60, >+ .lrate = 31, >+ .prate = 27, >+ .reg01 = 0x35, >+ .reg02 = 0xa0, >+ .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_625P_50, >+ .hres = 720, >+ .vres = 576, >+ .frate = 50, >+ .lrate = 31, >+ .prate = 27, >+ .reg01 = 0x36, >+ .reg02 = 0x00, >+ .reg03 = TVP7002_VCO_RANGE_ULOW | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_720P_60, >+ .hres = 1280, >+ .vres = 720, >+ .frate = 60, >+ .lrate = 45, >+ .prate = 74, >+ .reg01 = 0x67, >+ .reg02 = 0x20, >+ .reg03 = TVP7002_VCO_RANGE_MED | 0x20, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_720P_50, >+ .hres = 1280, >+ .vres = 720, >+ .frate = 50, >+ .lrate = 38, >+ .prate = 74, >+ .reg01 = 0x7b, >+ .reg02 = 0xc0, >+ .reg03 = TVP7002_VCO_RANGE_MED | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_1080I_60, >+ .hres = 1920, >+ .vres = 1080, >+ .frate = 60, >+ .lrate = 34, >+ .prate = 74, >+ .reg01 = 0x89, >+ .reg02 = 0x80, >+ .reg03 = TVP7002_VCO_RANGE_MED | 0x18, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_1080I_50, >+ .hres = 1920, >+ .vres = 1080, >+ .frate = 50, >+ .lrate = 28, >+ .prate = 74, >+ .reg01 = 0xa5, >+ .reg02 = 0x00, >+ .reg03 = TVP7002_VCO_RANGE_MED | 0x10, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_1080P_60, >+ .hres = 1920, >+ .vres = 1080, >+ .frate = 60, >+ .lrate = 68, >+ .prate = 149, >+ .reg01 = 0x89, >+ .reg02 = 0x80, >+ .reg03 = TVP7002_VCO_RANGE_HIGH | 0x20, >+ .reg04 = 0x80, >+ }, >+ { >+ .id = V4L2_STD_1080P_50, >+ .hres = 1920, >+ .vres = 1080, >+ .frate = 50, >+ .lrate = 56, >+ .prate = 149, >+ .reg01 = 0xa5, >+ .reg02 = 0x00, >+ .reg03 = TVP7002_VCO_RANGE_HIGH | 0x18, >+ .reg04 = 0x80, >+ }, >+}; >+ >+/* >+ * tvp7002_from_std - Map video standard to register information >+ * @std: v4l2_std_id (u64) integer >+ * >+ * Returns index of std or -1 in case of error. >+ */ >+int tvp7002_from_std(v4l2_std_id std) >+{ >+ int res; >+ >+ switch (std) { >+ case V4L2_STD_525P_60: >+ res = TVP7002_STD_480P; >+ break; >+ case V4L2_STD_525I_60: >+ res = TVP7002_STD_480I; >+ break; >+ case V4L2_STD_625P_50: >+ res = TVP7002_STD_576P; >+ break; >+ case V4L2_STD_625I_50: >+ res = TVP7002_STD_576I; >+ break; >+ case V4L2_STD_720P_50: >+ res = TVP7002_STD_720P_50; >+ break; >+ case V4L2_STD_720P_60: >+ res = TVP7002_STD_720P_60; >+ break; >+ case V4L2_STD_1080I_50: >+ res = TVP7002_STD_1080I_50; >+ break; >+ case V4L2_STD_1080I_60: >+ res = TVP7002_STD_1080I_60; >+ break; >+ case V4L2_STD_1080P_50: >+ res = TVP7002_STD_1080P_50; >+ break; >+ case V4L2_STD_1080P_60: >+ res = TVP7002_STD_1080P_60; >+ break; >+ default: >+ res = -1; >+ break; >+ } >+ >+ return res; >+} >+ >+/* Device definition */ >+struct tvp7002 { >+ struct v4l2_subdev sd; >+ v4l2_std_id video_mode; >+ struct v4l2_pix_format pix; >+ int streaming; >+}; >+ >+/* Supported controls */ >+static struct v4l2_queryctrl tvp7002_qctrl[] = { >+ { >+ /* This gain control uses fine grain in TVP7002 */ >+ .id = V4L2_CID_GAIN, >+ .type = V4L2_CTRL_TYPE_INTEGER, >+ .name = "Gain for RGB channels", >+ .minimum = 0, >+ .maximum = 255, >+ .step = 1, >+ .default_value = 0, >+ .flags = 0, >+ }, >+}; >+ >+/* >+ * to_tvp7002 - Obtain device handler TVP7002 >+ * @sd: ptr to v4l2_subdev struct >+ * >+ * Returns device handler tvp7002. >+ */ >+static struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd) >+{ >+ return container_of(sd, struct tvp7002, sd); >+} >+ >+/* >+ * tvp7002_read - Read a value from a register in an TVP7002 >+ * @sd: ptr to v4l2_subdev struct >+ * @reg: TVP7002 register address >+ * >+ * Returns value read if successful, or non-zero (-1) otherwise. >+ */ >+static int tvp7002_read(struct v4l2_subdev *sd, unsigned char addr) >+{ >+ struct i2c_client *c = v4l2_get_subdevdata(sd); >+ int retry; >+ int error; >+ >+ for (retry = 0; retry < I2C_RETRY_COUNT; retry++) { >+ error = i2c_smbus_read_byte_data(c, addr); >+ >+ if (error >= 0) >+ return error; >+ msleep_interruptible(10); >+ } >+ v4l2_err(sd, "TVP7002 read error %d\n", error); >+ return error; >+} >+ >+/* >+ * tvp7002_write() - Write a value to a register in TVP7002 >+ * @sd: ptr to v4l2_subdev struct >+ * @addr: TVP7002 register address >+ * @value: value to be written to the register >+ * >+ * Write a value to a register in an TVP7002 decoder device. >+ * Returns zero if successful, or non-zero otherwise. >+ */ >+static int tvp7002_write(struct v4l2_subdev *sd, u8 addr, u8 value) >+{ >+ struct i2c_client *c = v4l2_get_subdevdata(sd); >+ int retry; >+ int error; >+ >+ for (retry = 0; retry < I2C_RETRY_COUNT; retry++) { >+ error = i2c_smbus_write_byte_data(c, addr, value); >+ >+ if (error >= 0) >+ return error; >+ msleep_interruptible(10); >+ } >+ v4l2_err(sd, "TVP7002 write error %d\n", error); >+ return error; >+} >+ >+/* >+ * dump_reg_range() - Dump information from TVP7002 registers >+ * @sd: ptr to v4l2_subdev struct >+ * @init: TVP7002 start address >+ * @end: TVP7002 end address >+ * >+ * Dump values at a specified register range >+ * Returns nothing. >+ */ >+static void dump_reg_range(struct v4l2_subdev *sd, u8 init, const u8 end) >+{ >+ int i = 0; >+ int result; >+ >+ while (init != (u8)(end + 1)) { >+ result = tvp7002_read(sd, init); >+ >+ if (result < 0) >+ v4l2_err(sd, "tvp7002: reg 0x%02x unreadable\n", i); >+ else >+ v4l2_info(sd, "tvp7002: @0x%02x = %02x\n", i, result); >+ >+ init++; >+ i++; >+ } >+} >+ >+/* >+ * Macro for handling reading error conditions in tvp7002_log_status >+ */ >+#define TVP7002_LOG_CHK(reg, message, res) \ >+ do {\ >+ (res) = tvp7002_read(sd, (reg));\ >+ \ >+ if ((res) >= 0)\ >+ v4l2_info(sd, "%s = 0x%02x\n", (message), (res));\ >+ } while (0) >+/* >+ * tvp7002_log_status() - Print information about register settings >+ * @sd: ptr to v4l2_subdev struct >+ * >+ * Log register values of a TVP7002 decoder device. >+ * Returns zero or -EINVAL if read operation fails. >+ */ >+static int tvp7002_log_status(struct v4l2_subdev *sd) >+{ >+ int rres; >+ >+ TVP7002_LOG_CHK(TVP7002_CHIP_REV, "Chip revision number", rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_FDBK_DIV_LSBS, "H-PLL feedback div LSB", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_FDBK_DIV_MSBS, "H-PLL feedback div MSB", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_FDBK_DIV_MSBS, "VCO freq range selector", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_PHASE_SEL, "ADC sampling clk phase sel", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_CLAMP_START, "Clamp start", rres); >+ TVP7002_LOG_CHK(TVP7002_CLAMP_W, "Clamp width", rres); >+ TVP7002_LOG_CHK(TVP7002_HSYNC_OUT_W, "HSYNC output width", rres); >+ TVP7002_LOG_CHK(TVP7002_B_FINE_GAIN, "Digital fine grain B ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_G_FINE_GAIN, "Digital fine grain G ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_R_FINE_GAIN, "Digital fine grain R ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_B_FINE_OFF_MSBS, "Digital fine grain off B >ch", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_G_FINE_OFF_MSBS, "Digital fine grain off G >ch", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_R_FINE_OFF_MSBS, "Digital fine grain off R >ch", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_FINE_OFF_LSBS, "Dig fine grain off LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_SYNC_CTL_1, "Sync control 1", rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_AND_CLAMP_CTL, "H-PLL and clamp control", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_SYNC_ON_G_THRS, "Sync-On-Green threshold", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_SYNC_SEPARATOR_THRS, "Sync separator >thrshold", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_PRE_COAST, "H-PLL pre-coast", rres); >+ TVP7002_LOG_CHK(TVP7002_HPLL_POST_COAST, "H-PLL post-coast", rres); >+ TVP7002_LOG_CHK(TVP7002_SYNC_DETECT_STAT, "Sync detect status", >rres); >+ TVP7002_LOG_CHK(TVP7002_OUT_FORMATTER, "Output formatter", rres); >+ TVP7002_LOG_CHK(TVP7002_MISC_CTL_1, "Miscelaneous control 1", rres); >+ TVP7002_LOG_CHK(TVP7002_MISC_CTL_2, "Miscelaneous control 2", rres); >+ TVP7002_LOG_CHK(TVP7002_MISC_CTL_3, "Miscelaneous control 3", rres); >+ TVP7002_LOG_CHK(TVP7002_IN_MUX_SEL_1, "Input Mux Selector 1", rres); >+ TVP7002_LOG_CHK(TVP7002_IN_MUX_SEL_2, "Input Mux Selector 2", rres); >+ TVP7002_LOG_CHK(TVP7002_B_AND_G_COARSE_GAIN, "B and G coarse gain", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_R_COARSE_GAIN, "R coarse gain", rres); >+ TVP7002_LOG_CHK(TVP7002_B_COARSE_OFF, "Coarse offset for B ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_G_COARSE_OFF, "Coarse offset for G ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_R_COARSE_OFF, "Coarse offset for R ch", >rres); >+ TVP7002_LOG_CHK(TVP7002_HSOUT_OUT_START, "HSYNC lead edge out start", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_MISC_CTL_4, "Miscelaneous control 4", rres); >+ TVP7002_LOG_CHK(TVP7002_B_DGTL_ALC_OUT_LSBS, "Flt ALC out B ch LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_G_DGTL_ALC_OUT_LSBS, "Flt ALC out G ch LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_R_DGTL_ALC_OUT_LSBS, "Flt ALC out R ch LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_AUTO_LVL_CTL_ENABLE, "Auto level ctrl enable", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_DGTL_ALC_OUT_MSBS, "Filt ALC out RGB chs MSB", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_AUTO_LVL_CTL_FILTER, "Auto level ctrl filter", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_FINE_CLAMP_CTL, "Fine clamp control", rres); >+ TVP7002_LOG_CHK(TVP7002_PWR_CTL, "Power control", rres); >+ TVP7002_LOG_CHK(TVP7002_ADC_SETUP, "ADC setup", rres); >+ TVP7002_LOG_CHK(TVP7002_COARSE_CLAMP_CTL, "Coarse clamp ctrl", rres); >+ TVP7002_LOG_CHK(TVP7002_SOG_CLAMP, "Sync-On-Green clamp", rres); >+ TVP7002_LOG_CHK(TVP7002_RGB_COARSE_CLAMP_CTL, "RGB coarse clamp ctrl", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_SOG_COARSE_CLAMP_CTL, "SOG coarse clamp ctrl", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_ALC_PLACEMENT, "ALC placement", rres); >+ TVP7002_LOG_CHK(TVP7002_MVIS_STRIPPER_W, "Macrovision stripper width", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_SYNC_BYPASS, "Sync bypass", rres); >+ TVP7002_LOG_CHK(TVP7002_L_FRAME_STAT_LSBS, "Lines p Frame status >LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_L_FRAME_STAT_MSBS, "Lines p Frame status >MSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_CLK_L_STAT_LSBS, "Clks p line status LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_CLK_L_STAT_MSBS, "Clks p line status MSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_HSYNC_W, "HSYNC width", rres); >+ TVP7002_LOG_CHK(TVP7002_VSYNC_W, "VSYNC width", rres); >+ TVP7002_LOG_CHK(TVP7002_L_LENGTH_TOL, "Line length tolerance", rres); >+ TVP7002_LOG_CHK(TVP7002_VIDEO_BWTH_CTL, "Video bandwth control", >rres); >+ TVP7002_LOG_CHK(TVP7002_AVID_START_PIXEL_LSBS, "AVID start pixel >LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_AVID_START_PIXEL_MSBS, "AVID start pixel >MSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_AVID_STOP_PIXEL_LSBS, "AVID stop pixel LSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_AVID_STOP_PIXEL_MSBS, "AVID stop pixel MSBs", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_VBLK_F_0_START_L_OFF, "VBLK start line off 0", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_VBLK_F_1_START_L_OFF, "VBLK start line off 1", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_VBLK_F_0_DURATION, "VBLK duration 0", rres); >+ TVP7002_LOG_CHK(TVP7002_VBLK_F_1_DURATION, "VBLK duration 1", rres); >+ TVP7002_LOG_CHK(TVP7002_FBIT_F_0_START_L_OFF, "FBIT start line off 0", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_FBIT_F_1_START_L_OFF, "FBIT start line off 1", >+ rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_G_COEF_LSBS, "YUV Y G LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_G_COEF_MSBS, "YUV Y G MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_B_COEF_LSBS, "YUV Y B LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_B_COEF_MSBS, "YUV Y B MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_R_COEF_LSBS, "YUV Y R LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_Y_R_COEF_MSBS, "YUV Y R MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_G_COEF_LSBS, "YUV U G LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_G_COEF_MSBS, "YUV U G MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_B_COEF_LSBS, "YUV U B LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_B_COEF_MSBS, "YUV U B MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_R_COEF_LSBS, "YUV U R LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_U_R_COEF_MSBS, "YUV U R MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_G_COEF_LSBS, "YUV V G LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_G_COEF_MSBS, "YUV V G MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_B_COEF_LSBS, "YUV V B LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_B_COEF_MSBS, "YUV V B MSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_R_COEF_LSBS, "YUV V R LSBs", rres); >+ TVP7002_LOG_CHK(TVP7002_YUV_V_R_COEF_MSBS, "YUV V R MSBs", rres); >+ >+ return rres; >+} >+ >+/* >+ * tvp7002_g_chip_ident() - Get chip identification number >+ * @sd: ptr to v4l2_subdev struct >+ * @chip: ptr to v4l2_dbg_chip_ident struct >+ * >+ * Obtains the chip's identification number. >+ * Returns zero or -EINVAL if read operation fails. >+ */ >+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); >+ >+ if (rev < 0) >+ return -EINVAL; >+ >+ return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7002, >+ rev); >+} >+ >+/* >+ * tvp7002_write_inittab() - Write initialization values >+ * @sd: ptr to v4l2_subdev struct >+ * @regs: ptr to i2c_reg_value struct >+ * >+ * Write initialization values. >+ * Returns zero or -EINVAL if read operation fails. >+ */ >+static int tvp7002_write_inittab(struct v4l2_subdev *sd, >+ const struct i2c_reg_value *regs) >+{ >+ int i; >+ int error; >+ /* Initialize the first (defined) registers */ >+ while (regs->reg != 0x5c) { >+ error = tvp7002_write(sd, regs->reg, regs->value); >+ if (error < 0) >+ return -EINVAL; >+ regs++; >+ } >+ /* Initialize the last unnamed registers */ >+ for (i = 0x5c; i <= 0xff; i++) { >+ error = tvp7002_write(sd, i, 0x00); >+ if (error < 0) >+ return -EINVAL; >+ regs++; >+ } >+ >+ return 0; >+} >+ >+/* >+ * tvp7002_set_video_mode() >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @sdf: index to structure describing format >+ * >+ * Set video standard according to index >+ * >+ * Returns 0 if operation is successful or -EINVAL otherwise >+ */ >+static int tvp7002_set_video_mode(struct v4l2_subdev *sd, int sdf) >+{ >+ int error; >+ >+ if (sdf < TVP7002_STD_480I || sdf > TVP7002_STD_1080P_50) { >+ v4l2_err(sd, "sf out of range\n"); >+ return -ERANGE; >+ } >+ >+ /* Print specific information about current format */ >+ v4l2_info(sd, "Setting standard display format...\n"); >+ v4l2_info(sd, "hres = %d vres=%d fr=%d lr=%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 */ >+ error = tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_MSBS, >+ tvp7002_resolutions[sdf].reg01); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_LSBS, >+ tvp7002_resolutions[sdf].reg02); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_CRTL, >+ tvp7002_resolutions[sdf].reg03); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_PHASE_SEL, >+ tvp7002_resolutions[sdf].reg04); >+ if (error < 0) >+ return error; >+ >+ /* Set SD/HD mode registers */ >+ >+ if (sdf < TVP7002_STD_720P_60) { >+ error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x06); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x10); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x03); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x03); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0x17); >+ if (error < 0) >+ return error; >+ >+ if (sdf < TVP7002_STD_480P) { >+ error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, >+ 0x0c); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, >+ 0x24); >+ if (error < 0) >+ return error; >+ >+ } else { >+ error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, >+ 0x0a); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, >+ 0x12); >+ if (error < 0) >+ return error; >+ } >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x08); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x18); >+ if (error < 0) >+ return error; >+ } else { >+ error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x32); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x20); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x01); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0xc7); >+ if (error < 0) >+ return error; >+ >+ if(sdf < TVP7002_STD_1080I_60) { >+ error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, >+ 0x35); >+ if (error < 0) >+ return error; >+ } else { >+ error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, >+ 0x39); >+ if (error < 0) >+ return error; >+ } >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x5a); >+ if (error < 0) >+ return error; >+ >+ if(sdf < TVP7002_STD_1080P_60) { >+ error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, >+ 0x07); >+ if (error < 0) >+ return error; >+ } else { >+ error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, >+ 0x03); >+ if (error < 0) >+ return error; >+ } >+ } >+ if (sdf < TVP7002_STD_1080P_60) { >+ error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x50); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x0f); >+ if (error < 0) >+ return error; >+ } else { >+ error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x80); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x00); >+ if (error < 0) >+ return error; >+ } >+ /* Set up registers that hold the same value regardless of the >+ * SD mode >+ */ >+ error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, 0x5d); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); >+ if (error < 0) >+ return error; >+ >+ error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); >+ return error; >+} >+ >+/* >+ * tvp7002_get_video_mode() - V4L2 decoder interface handler for querystd >+ * @sd: pointer to standard V4L2 sub-device structure >+ * >+ * Returns the current standard detected by TVP7002. If no active input is >+ * detected, returns -1 >+ */ >+static v4l2_std_id tvp7002_get_video_mode(struct v4l2_subdev *sd) >+{ >+ v4l2_std_id error; >+ int reg01, reg02, reg03; >+ 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); >+ >+ if (reg01 < 0 || reg02 < 0 || reg03 < 0) { >+ error = V4L2_STD_UNKNOWN; >+ goto found_error; >+ } >+ >+ switch(reg01) { >+ case 0x35: >+ if (reg02 == 0xa0) >+ error = V4L2_STD_525I_60; >+ else >+ error = V4L2_STD_625I_50; >+ case 0x36: >+ if (reg02 == 0xa0) >+ error = V4L2_STD_525P_60; >+ else >+ error = V4L2_STD_625P_50; >+ break; >+ case 0x67: >+ error = V4L2_STD_720P_60; >+ break; >+ case 0x7b: >+ error = V4L2_STD_720P_50; >+ break; >+ case 0x89: >+ if (reg03 == 0x98) >+ error = V4L2_STD_1080I_60; >+ else >+ error = V4L2_STD_1080P_60; >+ break; >+ case 0xa5: >+ if (reg03 == 0x90) >+ error = V4L2_STD_1080I_50; >+ else >+ error = V4L2_STD_1080P_50; >+ break; >+ default: >+ error = V4L2_STD_UNKNOWN; >+ break; >+ } >+ >+found_error: >+ return error; >+} >+ >+/* >+ * tvp7002_querystd() - V4L2 decoder interface handler for querystd >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @std_id: standard V4L2 std_id ioctl enum >+ * >+ * Returns the current standard detected by TVP7002. If no active input is >+ * detected, returns -EINVAL >+ */ >+static int tvp7002_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) >+{ >+ struct tvp7002 *decoder = to_tvp7002(sd); >+ v4l2_std_id current_std; >+ u8 sync_lock_status; >+ int res; >+ >+ if (std_id == NULL) >+ return -EINVAL; >+ >+ /* get the current standard */ >+ res = tvp7002_get_video_mode(sd); >+ if (res == V4L2_STD_UNKNOWN) >+ return -EINVAL; >+ current_std = res; >+ >+ /* check whether signal is locked */ >+ sync_lock_status = tvp7002_read(sd, TVP7002_SYNC_DETECT_STAT); >+ >+ if (0x02 != (sync_lock_status & 0xff)) >+ return -EINVAL; /* No input detected */ >+ >+ decoder->video_mode = current_std; >+ *std_id = current_std; >+ >+ v4l2_info(sd, "Current STD: %d %d @ %d Hz\n", >+ tvp7002_resolutions[tvp7002_from_std(current_std)].hres, >+ tvp7002_resolutions[tvp7002_from_std(current_std)].vres, >+ tvp7002_resolutions[tvp7002_from_std(current_std)].frate); >+ return 0; >+} >+ >+/* >+ * tvp7002_scanmode() - Returns whether format is progressive >+ * or interlaced >+ */ >+ >+ >+/* >+ * tvp7002_try_fmt_cap() - V4L2 decoder interface handler for try_fmt >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure >+ * >+ * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This >+ * ioctl is used to negotiate the image capture size and pixel format >+ * without actually making it take effect. >+ */ >+static int tvp7002_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format >*f) >+{ >+ struct tvp7002 *decoder = to_tvp7002(sd); >+ struct v4l2_pix_format *pix; >+ v4l2_std_id current_std; >+ int res; >+ >+ if (f == NULL) >+ return -EINVAL; >+ >+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >+ /* only capture is supported */ >+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; >+ >+ pix = &f->fmt.pix; >+ >+ /* Calculate height and width based on current standard */ >+ res = tvp7002_get_video_mode(sd); >+ if (res < 0) >+ return -EINVAL; >+ current_std = res; >+ >+ decoder->video_mode = current_std; >+ pix->width = tvp7002_resolutions[tvp7002_from_std(current_std)].hres; >+ pix->height = >tvp7002_resolutions[tvp7002_from_std(current_std)].vres; >+ >+ pix->pixelformat = V4L2_PIX_FMT_UYVY; >+ >+ pix->field = V4L2_FIELD_INTERLACED; >+ pix->bytesperline = pix->width * 2; >+ pix->sizeimage = pix->bytesperline * pix->height; >+ pix->colorspace = V4L2_COLORSPACE_REC709; >+ pix->priv = 0; >+ >+ v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d" >+ "Width - %d, Height - %d", >+ "8-bit UYVY 4:2:2 Format", pix->bytesperline, >+ pix->width, pix->height); >+ return 0; >+} >+ >+/** >+ * tvp7002_s_fmt_cap() - V4L2 decoder interface handler for s_fmt >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure >+ * >+ * If the requested format is supported, configures the HW to use that >+ * format, returns error code if format not supported or HW can't be >+ * correctly configured. >+ */ >+static int tvp7002_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format >*f) >+{ >+ struct tvp7002 *decoder = to_tvp7002(sd); >+ struct v4l2_pix_format *pix; >+ int rval; >+ >+ if (f == NULL) >+ return -EINVAL; >+ >+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >+ /* only capture is supported */ >+ return -EINVAL; >+ >+ pix = &f->fmt.pix; >+ rval = tvp7002_try_fmt_cap(sd, f); >+ if (rval) >+ return rval; >+ >+ decoder->pix = *pix; >+ >+ return rval; >+} >+ >+/** >+ * tvp7002_g_fmt() - V4L2 decoder interface handler for tvp7002_g_fmt >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @f: pointer to standard V4L2 v4l2_format structure >+ * >+ * Returns the decoder's current pixel format in the v4l2_format >+ * parameter. >+ */ >+static int tvp7002_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) >+{ >+ struct tvp7002 *decoder = to_tvp7002(sd); >+ >+ if (f == NULL) >+ return -EINVAL; >+ >+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >+ /* only capture is supported */ >+ return -EINVAL; >+ >+ f->fmt.pix = decoder->pix; >+ >+ v4l2_info(sd, "Current FMT: bytesperline - %d" >+ "Width - %d, Height - %d", >+ decoder->pix.bytesperline, >+ decoder->pix.width, decoder->pix.height); >+ return 0; >+} >+ >+/* >+ * tvp7002_s_ctrl() - Set a control >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to v4l2_control struct >+ * >+ * Set a control for a TVP7002 decoder device. >+ * Returns zero when successful or -EINVAL if register access fails. >+ */ >+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 = tvp7002_from_std(std); >+ >+ v4l2_info(sd, "Set video std mode to %d.\n", (int)std); >+ >+ return tvp7002_set_video_mode(sd, vmd); >+} >+ >+/* >+ * tvp7002_g_ctrl() - Get a control >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to v4l2_control struct >+ * >+ * Get a control for a TVP7002 decoder device. >+ * Returns zero when successful or -EINVAL if register access fails. >+ */ >+static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control >*ctrl) >+{ >+ int rval, gval, bval; >+ int res; >+ >+ v4l2_info(sd, "g_ctrl called\n"); >+ >+ switch (ctrl->id) { >+ case V4L2_CID_GAIN: >+ rval = tvp7002_read(sd, TVP7002_R_FINE_GAIN); >+ gval = tvp7002_read(sd, TVP7002_G_FINE_GAIN); >+ bval = tvp7002_read(sd, TVP7002_B_FINE_GAIN); >+ >+ if (rval < 0 || gval < 0 || bval < 0) { >+ res = -1; >+ } else if (rval != gval || rval != bval) { >+ res = -1; >+ } else { >+ ctrl->value = rval & 0x0F; >+ res = ctrl->value; >+ } >+ break; >+ default: >+ res = -1; >+ break; >+ } >+ >+ return res < 0 ? res : 0; >+} >+ >+/* >+ * tvp7002_s_ctrl() - Set a control >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to v4l2_control struct >+ * >+ * Set a control in TVP7002 decoder device. >+ * Returns zero when successful or -EINVAL if register access fails. >+ */ >+static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control >*ctrl) >+{ >+ int rval, gval, bval; >+ int error; >+ u8 i, n; >+ n = ARRAY_SIZE(tvp7002_qctrl); >+ >+ for (i = 0; i < n; i++) >+ if (ctrl->id == tvp7002_qctrl[i].id) >+ break; >+ >+ if (i == n) >+ return -EINVAL; >+ >+ if (ctrl->value < tvp7002_qctrl[i].minimum || >+ ctrl->value > tvp7002_qctrl[i].maximum) >+ return -ERANGE; >+ >+ switch (ctrl->id) { >+ case V4L2_CID_GAIN: >+ rval = tvp7002_write(sd, TVP7002_R_FINE_GAIN, >+ ctrl->value & 0xff); >+ gval = tvp7002_write(sd, TVP7002_G_FINE_GAIN, >+ ctrl->value & 0xff); >+ bval = tvp7002_write(sd, TVP7002_B_FINE_GAIN, >+ ctrl->value & 0xff); >+ if (rval < 0 || gval < 0 || bval < 0) >+ error = -1; >+ else >+ error = rval; >+ break; >+ default: >+ error = -1; >+ break; >+ } >+ >+ if (error < 0) >+ return -EINVAL; >+ else >+ return 0; >+} >+ >+/* >+ * tvp7002_g_register() - Get the value of a register >+ * @sd: ptr to v4l2_subdev struct >+ * @vreg: ptr to v4l2_dbg_register struct >+ * >+ * Get the value of a TVP7002 decoder device register. >+ * Returns zero when successful, -EINVAL if register read fails or >+ * access to I2C client fails, -EPERM if the call is not allowed >+ * by diabled CAP_SYS_ADMIN. >+ */ >+#ifdef CONFIG_VIDEO_ADV_DEBUG >+static int tvp7002_g_register(struct v4l2_subdev *sd, >+ struct v4l2_dbg_register *reg) >+{ >+ struct i2c_client *client = v4l2_get_subdevdata(sd); >+ int error; >+ >+ 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; >+ >+ if (reg->val < 0) >+ error = -EINVAL; >+ else >+ error = 0; >+ >+ return error; >+} >+ >+/* >+ * tvp7002_s_register() - set a control >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to v4l2_control struct >+ * >+ * Get the value of a TVP7002 decoder device register. >+ * Returns zero when successful or -EINVAL if register read fails. >+ */ >+static int tvp7002_s_register(struct v4l2_subdev *sd, >+ struct v4l2_dbg_register *reg) >+{ >+ int error, wres; >+ 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; >+ >+ wres = tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); >+ >+ if (wres < 0) >+ error = -EINVAL; >+ else >+ error = 0; >+ >+ return error; >+} >+#endif >+ >+/* >+ * tvp7002_queryctrl() - Query a control >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to v4l2_queryctrl struct >+ * >+ * Query a control of a TVP7002 decoder device. >+ * Returns zero when successful or -EINVAL if register read fails. >+ */ >+static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl >*qc) >+{ >+ int i, error; >+ error = -EINVAL; >+ >+ v4l2_info(sd, "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)); >+ error = 0; >+ break; >+ } >+ >+ return error; >+} >+ >+/* >+ * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream >+ * @sd: pointer to standard V4L2 sub-device structure >+ * @enable: streaming enable or disable >+ * >+ * Sets streaming to enable or disable, if possible. >+ */ >+static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) >+{ >+ int err = 0; >+ struct tvp7002 *decoder = to_tvp7002(sd); >+ >+ if (decoder->streaming == enable) >+ return 0; >+ >+ if (enable) { >+ /* Power Up Sequence */ >+ err = tvp7002_write(sd, TVP7002_PWR_CTL, 0x00); >+ if (err) { >+ v4l2_err(sd, "Unable to turn on decoder\n"); >+ err = -EINVAL; >+ } >+ err = tvp7002_write_inittab(sd, tvp7002_init_default); >+ if (err < 0) { >+ v4l2_err(sd, "Unable to initialize\n"); >+ err = -EINVAL; >+ } >+ /* Detect if not already detected */ >+ err = tvp7002_read(sd, TVP7002_CHIP_REV); >+ if (err < 0) { >+ v4l2_err(sd, "Unable to detect decoder\n"); >+ err = -EINVAL; >+ } >+ decoder->streaming = enable; >+ } else { >+ /* Power Down Sequence */ >+ err = tvp7002_write(sd, TVP7002_PWR_CTL, 0x40); >+ if (err) { >+ v4l2_err(sd, "Unable to turn off decoder\n"); >+ return err; >+ } >+ decoder->streaming = enable; >+ } >+ >+ return err; >+} >+ >+/* Specific video subsystem operation handlers */ >+static const struct v4l2_subdev_video_ops tvp7002_video_ops = { >+ .querystd = tvp7002_querystd, >+ .s_stream = tvp7002_s_stream, >+ .g_fmt = tvp7002_g_fmt, >+}; >+ >+/* 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 >+}; >+ >+static const struct v4l2_subdev_ops tvp7002_ops = { >+ .core = &tvp7002_core_ops, >+ .video = &tvp7002_video_ops, >+}; >+ >+/* >+ * tvp7002_reset - Reset a TVP7002 device >+ * @sd: ptr to v4l2_subdev struct >+ * @val: unsigned integer (not used) >+ * >+ * Reset the TVP7002 device >+ * Returns zero when successful or -EINVAL if register read fails. >+ */ >+static int tvp7002_reset(struct v4l2_subdev *sd, u32 val) >+{ >+ int polarity; >+ int error; >+ >+ error = tvp7002_read(sd, TVP7002_CHIP_REV); >+ if (error < 0) { >+ error = -EINVAL; >+ goto found_error; >+ } >+ >+ if (error == 0x02) { >+ v4l2_info(sd, "rev. %02x detected.\n", error); >+ } else { >+ v4l2_info(sd, "unknown revision detected.\n"); >+ v4l2_info(sd, "revision number is %02x\n", error); >+ } >+ >+ /* Set polarity information */ >+ polarity = tvp7002_pdata.clk_polarity & tvp7002_pdata.hs_polarity & >+ tvp7002_pdata.vs_polarity & tvp7002_pdata.fid_polarity; >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, polarity); >+ if (error < 0) { >+ error = -EINVAL; >+ goto found_error; >+ } >+ >+ /* Initializes TVP7002 to its default values */ >+ error = tvp7002_write_inittab(sd, tvp7002_init_default); >+ if (error < 0) { >+ error = -EINVAL; >+ goto found_error; >+ } >+ >+found_error: >+ return error; >+}; >+ >+/* >+ * tvp7002_probe - Reset a TVP7002 device >+ * @sd: ptr to v4l2_subdev struct >+ * @ctrl: ptr to i2c_device_id struct >+ * >+ * Reset the TVP7002 device >+ * Returns zero when successful or -EINVAL if register read fails. >+ */ >+static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id >*id) >+{ >+ struct v4l2_subdev *sd; >+ struct tvp7002 *core; >+ int polarity; >+ int error; >+ >+ /* 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); >+ >+ /* Set polarity information */ >+ polarity = tvp7002_pdata.clk_polarity & tvp7002_pdata.hs_polarity & >+ tvp7002_pdata.vs_polarity & tvp7002_pdata.fid_polarity; >+ error = tvp7002_write(sd, TVP7002_MISC_CTL_2, polarity); >+ if (error < 0) { >+ error = -EINVAL; >+ goto found_error; >+ } >+ >+ /* Set video mode */ >+ core->video_mode = V4L2_STD_525P_60; >+ >+ if (debug > 1) >+ error = tvp7002_log_status(sd); >+ else >+ error = 0; >+ >+found_error: >+ if (error < 0) >+ kfree(core); >+ >+ return error; >+} >+ >+/* >+ * tvp7002_remove - Remove TVP7002 device support >+ * @c: ptr to i2c_client struct >+ * >+ * Reset the TVP7002 device >+ * Returns zero when successful or -EINVAL if register read fails. >+ */ >+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; >+} >+ >+/* I2C Device ID table */ >+static const struct i2c_device_id tvp7002_id[] = { >+ { "tvp7002", 0 }, >+ { } >+}; >+MODULE_DEVICE_TABLE(i2c, tvp7002_id); >+ >+/* I2C driver data */ >+static struct i2c_driver tvp7002_driver = { >+ .driver = { >+ .owner = THIS_MODULE, >+ .name = "tvp7002", >+ }, >+ .probe = tvp7002_probe, >+ .remove = tvp7002_remove, >+ .id_table = tvp7002_id, >+}; >-- >1.6.0.4 > _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source