Message ID | 1251418657-16240-1-git-send-email-santiago.nunez@ridgerun.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
> -----Original Message----- > From: davinci-linux-open-source-bounces@linux.davincidsp.com > [mailto:davinci-linux-open-source-bounces@linux.davincidsp.com] On > Behalf Of santiago.nunez@ridgerun.com > Sent: Friday, August 28, 2009 5:48 AM > To: Karicheri, Muralidharan > Cc: davinci-linux-open-source@linux.davincidsp.com; > clark.becker@ridgerun.com; Santiago Nunez-Corrales; > todd.fischer@ridgerun.com > Subject: [PATCH 5/6] TVP7002 driver for DM365 > > From: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com> > > This patch provides the implementation of the TVP7002 decoder > driver for DM365. g_fmt needs to be revised. > > Signed-off-by: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com> > --- > drivers/media/video/tvp7002.c | 3067 > +++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 3067 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..cc27aab > --- /dev/null > +++ b/drivers/media/video/tvp7002.c > @@ -0,0 +1,3067 @@ > +/* 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.nunez@ridgerun.com> > + * > + * This code is partially based upon the TVP5150 driver > + * written by Mauro Carvalho Chehab (mchehab@infradead.org) > + * and the TVP514x driver written by Vaibhav Hiremath > <hvaibhav@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 "tvp7002_reg.h" > + > +MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer > driver"); > +MODULE_AUTHOR("Santiago Nunez-Corrales > (santiago.nunez@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)"); > + > +/* 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 > + }, > + { /* Reserved */ > + 0x29, 0x08 > + }, [Hiremath, Vaibhav] Why do you want to mention reserved register here, and again in tvp7002_write_inittab function you are writing to these registers. I would suggest you not to mention reserved registers at all. > + { > + 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 > + }, [Hiremath, Vaibhav] same here. > + { > + 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 > + }, [Hiremath, Vaibhav] same. > + { > + 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 = V4L2_STD_480I_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_576I_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_480P_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_576P_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_480P_60: > + res = TVP7002_STD_480P; > + break; > + case V4L2_STD_480I_60: > + res = TVP7002_STD_480I; > + break; > + case V4L2_STD_576P_50: > + res = V4L2_STD_576P_50; > + break; > + case V4L2_STD_576I_50: > + res = V4L2_STD_576I_50; > + break; > + case V4L2_STD_720P_50: > + res = V4L2_STD_720P_50; > + break; > + case V4L2_STD_720P_60: > + res = V4L2_STD_720P_60; > + break; > + case V4L2_STD_1080I_50: > + res = V4L2_STD_1080I_50; > + break; > + case V4L2_STD_1080I_60: > + res = V4L2_STD_1080I_60; > + break; > + case V4L2_STD_1080P_50: > + res = V4L2_STD_1080P_50; > + break; > + case V4L2_STD_1080P_60: > + res = V4L2_STD_1080P_60; > + break; > + default: > + res = -1; > + break; > + } > + > + return res; > +} > + > +/* Device definition */ > +struct tvp7002 { > + struct v4l2_subdev sd; > + v4l2_std_id video_mode; > + int streaming; > +}; > + > +/* Supported controls */ > +static struct v4l2_queryctrl tvp7002_qctrl[] = { > + { > + .id = V4L2_CID_TVP7002_COARSE_GAIN_R, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Coarse gain for R channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_COARSE_GAIN_G, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Coarse gain for G channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_COARSE_GAIN_B, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Coarse gain for B channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_FINE_GAIN_R, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Fine gain for R channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_FINE_GAIN_G, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Fine gain for G channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_FINE_GAIN_B, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Fine gain for B channel", > + .minimum = 0, > + .maximum = 15, > + .step = 1, > + .default_value = 7, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_F_CLAMP_GB, > + .type = V4L2_CTRL_TYPE_BOOLEAN, > + .name = "Fine clamp for G and B", > + .minimum = 0, > + .maximum = 1, > + .step = 1, > + .default_value = 1, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_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_TVP7002_CLAMP_START, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Clamp start", > + .minimum = 0, > + .maximum = 255, > + .step = 1, > + .default_value = 0x32, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_CLAMP_W, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Clamp width", > + .minimum = 0, > + .maximum = 255, > + .step = 1, > + .default_value = 0x20, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_G_FINE_OFF, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Green fine offset", > + .minimum = 0, > + .maximum = 1024, > + .step = 1, > + .default_value = 512, > + .flags = 0, > + }, > + { > + .id = V4L2_CID_TVP7002_R_FINE_OFF, > + .type = V4L2_CTRL_TYPE_INTEGER, > + .name = "Red fine offset", > + .minimum = 0, > + .maximum = 1024, > + .step = 1, > + .default_value = 512, > + .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) > +{ > + int error; > + int retry = 0; > + struct i2c_client *c = v4l2_get_subdevdata(sd); > + > +try_read: > + error = i2c_smbus_read_byte_data(c, addr); > + if (error == -1){ > + if (retry <= I2C_RETRY_COUNT){ > + v4l2_warn(sd, "TVP7002 Read: retry ... %d\n", > retry); > + retry++; > + msleep_interruptible(10); > + goto try_read; > + } > + } > + > + return error; > +} > + > +/* > + * tvp7002_write() - Write a value to a register in TVP5146/47 > + * @sd: ptr to v4l2_subdev struct > + * @addr: TVP5146/47 register address [Hiremath, Vaibhav] Copy-Paste error, you may want to change this to tvp7002. > + * @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) > +{ > + int error; > + int retry = 0; > + struct i2c_client *c = v4l2_get_subdevdata(sd); > + > +write_again: > + error = i2c_smbus_write_byte_data(c, addr, value); > + if (error) { > + if (retry <= I2C_RETRY_COUNT) { > + v4l2_warn(sd, "TVP7002 Write: retry ... %d\n", > retry); > + retry++; > + msleep_interruptible(10); > + goto write_again; > + } > + } > + > + return error; > +} > + > +/* > + * dump_reg_range() - Dump information from TVP7002 registers > + * @sd: ptr to v4l2_subdev struct > + * @init: TVP7002 start address > + * @init: TVP7002 end address [Hiremath, Vaibhav] Should be "end" here. > + * @nline: register values per line > + * [Hiremath, Vaibhav] Do we have this argument coming in? > + * 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 == -1) > + v4l2_err(sd, "tvp7002: reg 0x%02x unreadable\n", > i); > + else > + v4l2_info(sd, "tvp7002: @0x%02x = %02x\n", i, > result); > + > + init++; > + i++; > + } > + printk("\n"); > +} > + > +/* > + * tvp7002_log_status() - Print information about register settings > + * @sd: ptr to v4l2_subdev struct > + * > + * Log regsiter values of a TVP7002 decoder device. > + * Returns zero or -EINVAL if read operation fails. > + */ > +static int tvp7002_log_status(struct v4l2_subdev *sd) > +{ > + int error, rres; > + > + rres = tvp7002_read(sd, TVP7002_CHIP_REV); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > TVP7002_CHIP_REV); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Chip revision number = > 0x%02x\n", > + TVP7002_CHIP_REV); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_FDBK_DIV_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: H-PLL feedback div LSB = > 0x%02x\n", > + TVP7002_HPLL_FDBK_DIV_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_FDBK_DIV_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: H-PLL feedback div MSB = > 0x%02x\n", > + TVP7002_HPLL_FDBK_DIV_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_CRTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > TVP7002_HPLL_CRTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VCO frequency range selector = > 0x%02x\n", > + TVP7002_HPLL_CRTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_PHASE_SEL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_PHASE_SEL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: ADC sampling clk phase select = > 0x%02x\n", > + TVP7002_HPLL_PHASE_SEL); > + } > + > + rres = tvp7002_read(sd, TVP7002_CLAMP_START); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_CLAMP_START); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Clamp start = 0x%02x\n", > + TVP7002_CLAMP_START); > + } > + > + rres = tvp7002_read(sd, TVP7002_CLAMP_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > TVP7002_CLAMP_W); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Clamp width = 0x%02x\n", > TVP7002_CLAMP_W); > + } > + > + rres = tvp7002_read(sd, TVP7002_HSYNC_OUT_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HSYNC_OUT_W); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: HSYNC output width = 0x%02x\n", > + TVP7002_HSYNC_OUT_W); > + } > + > + rres = tvp7002_read(sd, TVP7002_B_FINE_GAIN); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_B_FINE_GAIN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain for B ch = > 0x%02x\n", > + TVP7002_B_FINE_GAIN); > + } > + > + rres = tvp7002_read(sd, TVP7002_G_FINE_GAIN); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_G_FINE_GAIN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain for G ch = > 0x%02x\n", > + TVP7002_G_FINE_GAIN); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_FINE_GAIN); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_FINE_GAIN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain for R ch = > 0x%02x\n", > + TVP7002_R_FINE_GAIN); > + } > + > + rres = tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_B_FINE_OFF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain off B ch = > 0x%02x\n", > + TVP7002_B_FINE_OFF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_G_FINE_OFF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain off G ch = > 0x%02x\n", > + TVP7002_G_FINE_OFF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_FINE_OFF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Digital fine grain off R ch = > 0x%02x\n", > + TVP7002_R_FINE_OFF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_FINE_OFF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Dig fine grain off R ch LSBs = > 0x%02x\n", > + TVP7002_FINE_OFF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_SYNC_CTL_1); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SYNC_CTL_1); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: SYNC control 1 = 0x%02x\n", > + TVP7002_SYNC_CTL_1); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_AND_CLAMP_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_AND_CLAMP_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: H-PLL and clamp control = > 0x%02x\n", > + TVP7002_HPLL_AND_CLAMP_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SYNC_ON_G_THRS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Sync-On-Green threshold = > 0x%02x\n", > + TVP7002_SYNC_ON_G_THRS); > + } > + > + rres = tvp7002_read(sd, TVP7002_SYNC_SEPARATOR_THRS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SYNC_SEPARATOR_THRS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Sync separator threshold = > 0x%02x\n", > + TVP7002_SYNC_SEPARATOR_THRS); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_PRE_COAST); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_PRE_COAST); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: H-PLL pre-coast = 0x%02x\n", > + TVP7002_HPLL_PRE_COAST); > + } > + > + rres = tvp7002_read(sd, TVP7002_HPLL_POST_COAST); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HPLL_POST_COAST); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: H-PLL post-coast = 0x%02x\n", > + TVP7002_HPLL_POST_COAST); > + } > + > + rres = tvp7002_read(sd, TVP7002_SYNC_DETECT_STAT); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SYNC_DETECT_STAT); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Sync detect status = 0x%02x\n", > + TVP7002_SYNC_DETECT_STAT); > + } > + > + rres = tvp7002_read(sd, TVP7002_OUT_FORMATTER); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_OUT_FORMATTER); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Output formatter = 0x%02x\n", > + TVP7002_OUT_FORMATTER); > + } > + > + rres = tvp7002_read(sd, TVP7002_MISC_CTL_1); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MISC_CTL_1); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Miscelaneous control 1 = > 0x%02x\n", > + TVP7002_MISC_CTL_1); > + } > + > + rres = tvp7002_read(sd, TVP7002_MISC_CTL_2); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MISC_CTL_2); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Miscelaneous control 2 = > 0x%02x\n", > + TVP7002_MISC_CTL_2); > + } > + > + rres = tvp7002_read(sd, TVP7002_MISC_CTL_3); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MISC_CTL_3); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Miscelaneous control 3 = > 0x%02x\n", > + TVP7002_MISC_CTL_3); > + } > + > + rres = tvp7002_read(sd, TVP7002_MISC_CTL_3); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MISC_CTL_3); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Miscelaneous control 3 = > 0x%02x\n", > + TVP7002_MISC_CTL_3); > + } > + > + rres = tvp7002_read(sd, TVP7002_IN_MUX_SEL_1); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_IN_MUX_SEL_1); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Input Mux Selector 1 = > 0x%02x\n", > + TVP7002_IN_MUX_SEL_1); > + } > + > + rres = tvp7002_read(sd, TVP7002_IN_MUX_SEL_2); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_IN_MUX_SEL_2); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Input Mux Selector 1 = > 0x%02x\n", > + TVP7002_IN_MUX_SEL_2); > + } > + > + rres = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_B_AND_G_COARSE_GAIN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: B and G coarse gain = 0x%02x\n", > + TVP7002_B_AND_G_COARSE_GAIN); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_COARSE_GAIN); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_COARSE_GAIN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: R coarse gain = 0x%02x\n", > + TVP7002_R_COARSE_GAIN); > + } > + > + rres = tvp7002_read(sd, TVP7002_B_COARSE_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_B_COARSE_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Coarse offset for B ch = > 0x%02x\n", > + TVP7002_B_COARSE_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_G_COARSE_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_G_COARSE_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Coarse offset for G ch = > 0x%02x\n", > + TVP7002_G_COARSE_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_COARSE_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_COARSE_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Coarse offset for R ch = > 0x%02x\n", > + TVP7002_R_COARSE_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_COARSE_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_COARSE_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Coarse offset for R ch = > 0x%02x\n", > + TVP7002_R_COARSE_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_HSOUT_OUT_START); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HSOUT_OUT_START); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: HSYNC lead edge out start = > 0x%02x\n", > + TVP7002_HSOUT_OUT_START); > + } > + > + rres = tvp7002_read(sd, TVP7002_MISC_CTL_4); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MISC_CTL_4); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Miscelaneous control 4 = > 0x%02x\n", > + TVP7002_MISC_CTL_4); > + } > + > + rres = tvp7002_read(sd, TVP7002_B_DGTL_ALC_OUT_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_B_DGTL_ALC_OUT_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Filt ALC out for B ch LSBs = > 0x%02x\n", > + TVP7002_B_DGTL_ALC_OUT_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_G_DGTL_ALC_OUT_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_G_DGTL_ALC_OUT_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Filt ALC out for G ch LSBs = > 0x%02x\n", > + TVP7002_G_DGTL_ALC_OUT_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_R_DGTL_ALC_OUT_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_R_DGTL_ALC_OUT_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Filt ALC out for R ch LSBs = > 0x%02x\n", > + TVP7002_R_DGTL_ALC_OUT_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_ENABLE); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AUTO_LVL_CTL_ENABLE); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Auto level control enable = > 0x%02x\n", > + TVP7002_AUTO_LVL_CTL_ENABLE); > + } > + > + rres = tvp7002_read(sd, TVP7002_DGTL_ALC_OUT_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_DGTL_ALC_OUT_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Filt ALC out RGB chs MSB = > 0x%02x\n", > + TVP7002_DGTL_ALC_OUT_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_FILTER); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AUTO_LVL_CTL_FILTER); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Auto level control filter = > 0x%02x\n", > + TVP7002_AUTO_LVL_CTL_FILTER); > + } > + > + rres = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_FINE_CLAMP_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Fine clamp control = 0x%02x\n", > + TVP7002_FINE_CLAMP_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_PWR_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_PWR_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Power control = 0x%02x\n", > + TVP7002_PWR_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_ADC_SETUP); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_ADC_SETUP); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: ADC setup = 0x%02x\n", > + TVP7002_ADC_SETUP); > + } > + > + rres = tvp7002_read(sd, TVP7002_COARSE_CLAMP_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_COARSE_CLAMP_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Coarse clamp control = > 0x%02x\n", > + TVP7002_COARSE_CLAMP_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_SOG_CLAMP); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SOG_CLAMP); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Sync-On-Green clamp = 0x%02x\n", > + TVP7002_SOG_CLAMP); > + } > + > + rres = tvp7002_read(sd, TVP7002_RGB_COARSE_CLAMP_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_RGB_COARSE_CLAMP_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: RGB coarse clamp control = > 0x%02x\n", > + TVP7002_RGB_COARSE_CLAMP_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_SOG_COARSE_CLAMP_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SOG_COARSE_CLAMP_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: SOG coarse clamp control = > 0x%02x\n", > + TVP7002_SOG_COARSE_CLAMP_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_ALC_PLACEMENT); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_ALC_PLACEMENT); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: ALC placement = 0x%02x\n", > + TVP7002_ALC_PLACEMENT); > + } > + > + rres = tvp7002_read(sd, TVP7002_MVIS_STRIPPER_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_MVIS_STRIPPER_W); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Macrovision stripper width = > 0x%02x\n", > + TVP7002_VSYNC_ALGN); > + } > + > + rres = tvp7002_read(sd, TVP7002_MVIS_STRIPPER_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VSYNC_ALGN); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VSYNC alignment = 0x%02x\n", > + TVP7002_VSYNC_ALGN); > + } > + > + rres = tvp7002_read(sd, TVP7002_SYNC_BYPASS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_SYNC_BYPASS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Sync bypass = 0x%02x\n", > + TVP7002_SYNC_BYPASS); > + } > + > + rres = tvp7002_read(sd, TVP7002_L_FRAME_STAT_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_L_FRAME_STAT_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Lines p Frame status LSBs = > 0x%02x\n", > + TVP7002_L_FRAME_STAT_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_L_FRAME_STAT_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_L_FRAME_STAT_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Lines p Frame status MSBs = > 0x%02x\n", > + TVP7002_L_FRAME_STAT_MSBS); > + } > + > + > + rres = tvp7002_read(sd, TVP7002_CLK_L_STAT_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_CLK_L_STAT_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Clks p line status LSBs = > 0x%02x\n", > + TVP7002_CLK_L_STAT_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_CLK_L_STAT_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_CLK_L_STAT_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Clks p line status MSBs = > 0x%02x\n", > + TVP7002_CLK_L_STAT_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_HSYNC_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_HSYNC_W); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: HSYNC width = 0x%02x\n", > + TVP7002_HSYNC_W); > + } > + > + rres = tvp7002_read(sd, TVP7002_VSYNC_W); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VSYNC_W); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VSYNC width = 0x%02x\n", > + TVP7002_VSYNC_W); > + } > + > + rres = tvp7002_read(sd, TVP7002_L_LENGTH_TOL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_L_LENGTH_TOL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Line length tolerance = > 0x%02x\n", > + TVP7002_L_LENGTH_TOL); > + } > + > + rres = tvp7002_read(sd, TVP7002_VIDEO_BWTH_CTL); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VIDEO_BWTH_CTL); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: Video bandwidth control = > 0x%02x\n", > + TVP7002_VIDEO_BWTH_CTL); > + } > + > + rres = tvp7002_read(sd, TVP7002_AVID_START_PIXEL_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AVID_START_PIXEL_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: AVID start pixel LSBs = > 0x%02x\n", > + TVP7002_AVID_START_PIXEL_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_AVID_START_PIXEL_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AVID_START_PIXEL_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: AVID start pixel MSBs = > 0x%02x\n", > + TVP7002_AVID_START_PIXEL_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AVID_STOP_PIXEL_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: AVID stop pixel LSBs = > 0x%02x\n", > + TVP7002_AVID_STOP_PIXEL_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_AVID_STOP_PIXEL_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: AVID stop pixel MSBs = > 0x%02x\n", > + TVP7002_AVID_STOP_PIXEL_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_VBLK_F_0_START_L_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VBLK_F_0_START_L_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VBLK start line offset 0 = > 0x%02x\n", > + TVP7002_VBLK_F_0_START_L_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_VBLK_F_1_START_L_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VBLK_F_1_START_L_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VBLK start line offset 1 = > 0x%02x\n", > + TVP7002_VBLK_F_1_START_L_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_VBLK_F_0_DURATION); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VBLK_F_0_DURATION); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VBLK duration 0 = 0x%02x\n", > + TVP7002_VBLK_F_0_DURATION); > + } > + > + rres = tvp7002_read(sd, TVP7002_VBLK_F_1_DURATION); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_VBLK_F_1_DURATION); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: VBLK duration 1 = 0x%02x\n", > + TVP7002_VBLK_F_1_DURATION); > + } > + > + rres = tvp7002_read(sd, TVP7002_FBIT_F_0_START_L_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_FBIT_F_0_START_L_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: F-bit start line offset 0 = > 0x%02x\n", > + TVP7002_FBIT_F_0_START_L_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_FBIT_F_1_START_L_OFF); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_FBIT_F_1_START_L_OFF); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: F-bit start line offset 1 = > 0x%02x\n", > + TVP7002_FBIT_F_1_START_L_OFF); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_G_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y G LSBs = 0x%02x\n", > + TVP7002_YUV_Y_G_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_G_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y G MSBs = 0x%02x\n", > + TVP7002_YUV_Y_G_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_B_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y B LSBs = 0x%02x\n", > + TVP7002_YUV_Y_B_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_B_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y B MSBs = 0x%02x\n", > + TVP7002_YUV_Y_B_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_R_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y R LSBs = 0x%02x\n", > + TVP7002_YUV_Y_R_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_Y_R_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV Y R MSBs = 0x%02x\n", > + TVP7002_YUV_Y_R_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_G_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_G_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U G LSBs = 0x%02x\n", > + TVP7002_YUV_U_G_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_G_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_G_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U G MSBs = 0x%02x\n", > + TVP7002_YUV_U_G_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_B_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_B_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U B LSBs = 0x%02x\n", > + TVP7002_YUV_U_B_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_B_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_B_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U B MSBs = 0x%02x\n", > + TVP7002_YUV_U_B_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_R_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_R_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U R LSBs = 0x%02x\n", > + TVP7002_YUV_U_R_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_U_R_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_U_R_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV U R MSBs = 0x%02x\n", > + TVP7002_YUV_U_R_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_G_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_G_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V G LSBs = 0x%02x\n", > + TVP7002_YUV_V_G_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_G_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_G_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V G MSBs = 0x%02x\n", > + TVP7002_YUV_V_G_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_B_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_B_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V B LSBs = 0x%02x\n", > + TVP7002_YUV_V_B_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_B_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_B_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V B MSBs = 0x%02x\n", > + TVP7002_YUV_V_B_COEF_MSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_R_COEF_LSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_R_COEF_LSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V R LSBs = 0x%02x\n", > + TVP7002_YUV_V_R_COEF_LSBS); > + } > + > + rres = tvp7002_read(sd, TVP7002_YUV_V_R_COEF_MSBS); > + if (rres == -1){ > + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", > + TVP7002_YUV_V_R_COEF_MSBS); > + error = -EINVAL; > + goto found_error; > + } > + else { > + v4l2_info(sd, "tvp7002: YUV V R MSBs = 0x%02x\n", > + TVP7002_YUV_V_R_COEF_MSBS); > + } > + [Hiremath, Vaibhav] Can we have some macro/inline function based implementation here? > + error = 0; > + > +found_error: > + return error; > +} > + > +/* > + * 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 == -1) > + return -EINVAL; > + else > + 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 == -1){ > + error = -EINVAL; > + goto found_error; [Hiremath, Vaibhav] No need for goto, you can directly return from here. > + } > + else { > + regs++; > + } > + } > + /* Initialize the last (undefined) registers */ > + for (i = 0x5c; i <= 0xff; i++){ > + error = tvp7002_write(sd, i, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + else { > + regs++; > + } > + } [Hiremath, Vaibhav] I am not sure whether this is really required here, since they are undefined. > + > + error = 0; > + > +found_error: > + return error; > +} > + > +/* > + * 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, "tvp7002: sf out of range\n"); > + error = -ERANGE; > + goto found_error; > + } > + > + /* Print specific information about current format */ > + v4l2_info(sd, "tvp7002: Setting standard display > format...\n"); > + v4l2_info(sd, "tvp7002: 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 == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + error = tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_LSBS, > + tvp7002_resolutions[sdf].reg02); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + error = tvp7002_write(sd, TVP7002_HPLL_CRTL, > tvp7002_resolutions[sdf].reg03); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + error = tvp7002_write(sd, TVP7002_HPLL_PHASE_SEL, > + tvp7002_resolutions[sdf].reg04); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + /* Set SD/HD mode registers */ > + > + if (sdf < TVP7002_STD_720P_60){ > + error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x06); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x10); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x03); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, > 0x03); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0x17); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + if (sdf < TVP7002_STD_480P){ > + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, > 0x0c); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, > 0x24); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + else { > + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, > 0x0a); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, > 0x12); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x08); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x18); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + else { > + error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x32); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x20); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x01); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, > 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0xc7); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + if(sdf < TVP7002_STD_1080I_60){ > + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, > 0x35); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + else { > + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, > 0x39); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x5a); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + if(sdf < TVP7002_STD_1080P_60){ > + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, > 0x07); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + else { > + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, > 0x03); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + } > + if (sdf < TVP7002_STD_1080P_60){ > + error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x50); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x0f); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + } > + else { > + error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x80); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_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 == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + error = 0; > + [Hiremath, Vaibhav] I think there is no need for goto here, since we are not cleaning up anything on failure. So we can return directly. Applies to all the places of I2C read/write. > +found_error: > + 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){ > + int 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 == -1 || reg02 == -1 || reg03 == -1){ > + error = -1; > + goto found_error; > + } > + > + switch(reg01){ > + case 0x35: > + if (reg02 == 0xa0) > + error = V4L2_STD_480I_60; > + else > + error = V4L2_STD_576I_50; > + case 0x36: > + if (reg02 == 0xa0) > + error = V4L2_STD_480P_60; > + else > + error = V4L2_STD_576P_50; > + case 0x67: > + error = V4L2_STD_720P_60; > + case 0x7b: > + error = V4L2_STD_720P_50; > + case 0x89: > + if (reg03 == 0x98) > + error = V4L2_STD_1080I_60; > + else > + error = V4L2_STD_1080P_60; > + case 0xa5: > + if (reg03 == 0x90) > + error = V4L2_STD_1080I_50; > + else > + error = V4L2_STD_1080P_50; > + default: > + error = -1; > + } > + > +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, lock_mask; > + > + if (std_id == NULL) > + return -EINVAL; > + > + /* get the current standard */ > + current_std = tvp7002_get_video_mode(sd); > + if (current_std == -1) > + return -EINVAL; > + > + /* 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: %s", decoder->video_mode); > + return 0; > +} > + > +/** > + * 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);*/ [Hiremath, Vaibhav] This is commented, is this intentional or mistake? > + 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 res; > + int tmp; > + > + v4l2_info(sd, "tvp7002: g_ctrl called\n"); > + > + switch (ctrl->id) { > + case V4L2_CID_TVP7002_COARSE_GAIN_R: > + res = tvp7002_read(sd, TVP7002_R_COARSE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x0F; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_COARSE_GAIN_G: > + res = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res & 0xF0) >> 4; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_COARSE_GAIN_B: > + res = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x0F; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_R: > + res = tvp7002_read(sd, TVP7002_R_FINE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0xFF; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_G: > + res = tvp7002_read(sd, TVP7002_G_FINE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0xFF; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_B: > + res = tvp7002_read(sd, TVP7002_B_FINE_GAIN); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0xFF; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_B_CLAMP: > + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res >> 2) & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_G_CLAMP: > + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res >> 1) & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_R_CLAMP: > + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_CLAMP_OFF_EN: > + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res >> 7) & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_FCTCA: > + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (((res >> 3) & 0x03) == 0x03) ? 1 : > 0; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_F_CLAMP_GB: > + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res >> 1) & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_F_CLAMP_R: > + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x01; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_CLAMP_START: > + res = tvp7002_read(sd, TVP7002_CLAMP_START); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0xff; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_CLAMP_W: > + res = tvp7002_read(sd, TVP7002_CLAMP_W); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0xff; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_B_COARSE_OFF: > + res = tvp7002_read(sd, TVP7002_B_COARSE_OFF); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x3f; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_G_COARSE_OFF: > + res = tvp7002_read(sd, TVP7002_G_COARSE_OFF); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x3f; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_R_COARSE_OFF: > + res = tvp7002_read(sd, TVP7002_R_COARSE_OFF); > + if (res == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = res & 0x3f; > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_B_FINE_OFF: > + res = tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS); > + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); > + if (res == -1 || tmp == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res << 2) | (tmp & 0x03); > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_G_FINE_OFF: > + res = tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS); > + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); > + if (res == -1 || tmp == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res << 2) | ((tmp >> 2) & 0x03); > + res = ctrl->value; > + } > + break; > + case V4L2_CID_TVP7002_R_FINE_OFF: > + res = tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS); > + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); > + if (res == -1 || tmp == -1){ > + res = -EINVAL; > + goto found_error; > + } > + else { > + ctrl->value = (res << 2) | ((tmp >> 4) & 0x03); > + res = ctrl->value; > + } [Hiremath, Vaibhav] All the above cases we can implement something - case V4L2_CID_TVP7002_R_FINE_OFF: res = tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS); if (res != -1){ ctrl->value = (res << 2) | ((tmp >> 4) & 0x03); res = ctrl->value; } Break; This will directly return the error value returned by I2C read in res. > + break; > + default: > + res = -EINVAL; > + break; > + } > + > +found_error: > + return res; > +} > + > +/* > + * 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 error; > + 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_err(sd, "s_ctrl: id=%d, value=%d\n", ctrl->id, > + ctrl->value); > + break; > + } > + > + switch (ctrl->id) { > + case V4L2_CID_TVP7002_COARSE_GAIN_R: > + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, > + ctrl->value & 0xff); > + break; > + case V4L2_CID_TVP7002_COARSE_GAIN_G: > + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, > + (ctrl->value << 4) & 0xf0); > + break; > + case V4L2_CID_TVP7002_COARSE_GAIN_B: > + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, > + ctrl->value& 0x0f); > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_R: > + error = tvp7002_write(sd, TVP7002_R_FINE_GAIN, > + ctrl->value & 0xff); > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_G: > + error = tvp7002_write(sd, TVP7002_G_FINE_GAIN, > + (ctrl->value << 4) & 0xf0); > + break; > + case V4L2_CID_TVP7002_FINE_GAIN_B: > + error = tvp7002_write(sd, TVP7002_B_FINE_GAIN, > + ctrl->value& 0x0f); > + break; > + case V4L2_CID_TVP7002_B_CLAMP: > + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, > + (ctrl->value << 2) & 0x04); > + break; > + case V4L2_CID_TVP7002_G_CLAMP: > + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, > + (ctrl->value << 1) & 0x02); > + break; > + case V4L2_CID_TVP7002_R_CLAMP: > + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, > + ctrl->value & 0x01); > + break; > + case V4L2_CID_TVP7002_CLAMP_OFF_EN: > + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, > + (ctrl->value << 7) & 0x80); > + break; > + case V4L2_CID_TVP7002_FCTCA: > + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, > + ((ctrl->value == 0 ? 0x00 : 0x03) << 3) & > 0x0c); > + break; > + case V4L2_CID_TVP7002_F_CLAMP_GB: > + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, > + (ctrl->value << 1) & 0x02); > + break; > + case V4L2_CID_TVP7002_F_CLAMP_R: > + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, > + ctrl->value & 0x01); > + break; > + case V4L2_CID_TVP7002_CLAMP_START: > + error = tvp7002_write(sd, TVP7002_CLAMP_START, > + ctrl->value & 0xff); > + break; > + case V4L2_CID_TVP7002_CLAMP_W: > + error = tvp7002_write(sd, TVP7002_CLAMP_W, ctrl->value & > 0xff); > + break; > + case V4L2_CID_TVP7002_B_COARSE_OFF: > + error = tvp7002_write(sd, TVP7002_B_COARSE_OFF, > + ctrl->value & 0x3f); > + break; > + case V4L2_CID_TVP7002_G_COARSE_OFF: > + error = tvp7002_write(sd, TVP7002_G_COARSE_OFF, > + ctrl->value & 0x3f); > + break; > + case V4L2_CID_TVP7002_R_COARSE_OFF: > + error = tvp7002_write(sd, TVP7002_R_COARSE_OFF, > + ctrl->value & 0x3f); > + break; > + case V4L2_CID_TVP7002_B_FINE_OFF: > + error = tvp7002_write(sd, TVP7002_B_FINE_OFF_MSBS, > + (ctrl->value & 0xff) >> 2) | > + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, > + ctrl->value & 0x03); > + break; > + case V4L2_CID_TVP7002_G_FINE_OFF: > + error = tvp7002_write(sd, TVP7002_G_FINE_OFF_MSBS, > + (ctrl->value & 0xff) >> 2) | > + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, > + (ctrl->value & 0x03) << 2); > + break; > + case V4L2_CID_TVP7002_R_FINE_OFF: > + error = tvp7002_write(sd, TVP7002_R_FINE_OFF_MSBS, > + (ctrl->value & 0xff) >> 2) | > + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, > + (ctrl->value & 0x03) << 4); > + break; > + default: > + error = -1; > + break; > + } > + > + if (error == -1) > + 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) > +{ > + int error; > + > + struct i2c_client *client = v4l2_get_subdevdata(sd); > + > + if (!v4l2_chip_match_i2c_client(client, ®->match)){ > + error = -EINVAL; > + goto found_error; > + } > + if (!capable(CAP_SYS_ADMIN)){ > + error = -EPERM; > + goto found_error; > + } > + > + reg->val = tvp7002_read(sd, reg->reg & 0xff); > + reg->size = 1; > + > + if (reg->val == -1) > + error = -EINVAL; > + else > + error = 0; > +found_error: > + 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)){ > + error = -EINVAL; > + goto found_error; > + } > + if (!capable(CAP_SYS_ADMIN)){ > + error = -EPERM; > + goto found_error; > + } > + > + wres = tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); > + > + if (wres == -1) > + error = -EINVAL; > + else > + error = 0; > + > +found_error: > + 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; > + > + v4l2_info(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)); > + error = 0; > + } > + > + error = -EINVAL; > + > + return error; [Hiremath, Vaibhav] I am confused here, what are you trying to do here. Queryctrl will always be return -EINVAL. Thanks, Vaibhav > +} > + > +/** > + * 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; > + > + switch (enable) { > + case 0: > + { > + /* 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; > + break; > + } > + case 1: > + { > + /* 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 == -1) { > + v4l2_err(sd, "Unable to initialize\n"); > + err = -EINVAL; > + } > + /* Detect if not already detected */ > + err = tvp7002_read(sd, TVP7002_CHIP_REV); > + if (err == -1) { > + v4l2_err(sd, "Unable to detect decoder\n"); > + err = -EINVAL; > + } > + decoder->streaming = enable; > + break; > + } > + default: > + { > + err = -ENODEV; > + break; > + } > + } > + > + 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 error; > + int polarity; > + > + error = tvp7002_read(sd, TVP7002_CHIP_REV); > + if (error == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + if (error == 0x02) > + v4l2_info(sd, "tvp7002: rev. %02x detected.\n", error); > + > + else { > + v4l2_info(sd, "tvp7002: unknown revision detected.\n"); > + v4l2_info(sd, "tvp7002: 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 == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + /* Initializes TVP7002 to its default values */ > + error = tvp7002_write_inittab(sd, tvp7002_init_default); > + if (error == -1){ > + 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) > +{ > + int error; > + int polarity; > + 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)){ > + error = -EIO; > + } > + > + core = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); > + > + if (!core) { > + error = -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 == -1){ > + error = -EINVAL; > + goto found_error; > + } > + > + /* Set video mode */ > + core->video_mode = V4L2_STD_480P_60; > + > + if (debug > 1) > + error = tvp7002_log_status(sd); > + else > + error = 0; > + > +found_error: > + 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 v4l2_i2c_driver_data v4l2_i2c_data = { > + .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
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c new file mode 100644 index 0000000..cc27aab --- /dev/null +++ b/drivers/media/video/tvp7002.c @@ -0,0 +1,3067 @@ +/* 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.nunez@ridgerun.com> + * + * This code is partially based upon the TVP5150 driver + * written by Mauro Carvalho Chehab (mchehab@infradead.org) + * and the TVP514x driver written by Vaibhav Hiremath <hvaibhav@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 "tvp7002_reg.h" + +MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver"); +MODULE_AUTHOR("Santiago Nunez-Corrales (santiago.nunez@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)"); + +/* 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 + }, + { /* 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 = V4L2_STD_480I_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_576I_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_480P_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_576P_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_480P_60: + res = TVP7002_STD_480P; + break; + case V4L2_STD_480I_60: + res = TVP7002_STD_480I; + break; + case V4L2_STD_576P_50: + res = V4L2_STD_576P_50; + break; + case V4L2_STD_576I_50: + res = V4L2_STD_576I_50; + break; + case V4L2_STD_720P_50: + res = V4L2_STD_720P_50; + break; + case V4L2_STD_720P_60: + res = V4L2_STD_720P_60; + break; + case V4L2_STD_1080I_50: + res = V4L2_STD_1080I_50; + break; + case V4L2_STD_1080I_60: + res = V4L2_STD_1080I_60; + break; + case V4L2_STD_1080P_50: + res = V4L2_STD_1080P_50; + break; + case V4L2_STD_1080P_60: + res = V4L2_STD_1080P_60; + break; + default: + res = -1; + break; + } + + return res; +} + +/* Device definition */ +struct tvp7002 { + struct v4l2_subdev sd; + v4l2_std_id video_mode; + int streaming; +}; + +/* Supported controls */ +static struct v4l2_queryctrl tvp7002_qctrl[] = { + { + .id = V4L2_CID_TVP7002_COARSE_GAIN_R, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for R channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_COARSE_GAIN_G, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for G channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_COARSE_GAIN_B, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Coarse gain for B channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_FINE_GAIN_R, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for R channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_FINE_GAIN_G, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for G channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_FINE_GAIN_B, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Fine gain for B channel", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 7, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_F_CLAMP_GB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fine clamp for G and B", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_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_TVP7002_CLAMP_START, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Clamp start", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x32, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_CLAMP_W, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Clamp width", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x20, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_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_TVP7002_G_FINE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Green fine offset", + .minimum = 0, + .maximum = 1024, + .step = 1, + .default_value = 512, + .flags = 0, + }, + { + .id = V4L2_CID_TVP7002_R_FINE_OFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red fine offset", + .minimum = 0, + .maximum = 1024, + .step = 1, + .default_value = 512, + .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) +{ + int error; + int retry = 0; + struct i2c_client *c = v4l2_get_subdevdata(sd); + +try_read: + error = i2c_smbus_read_byte_data(c, addr); + if (error == -1){ + if (retry <= I2C_RETRY_COUNT){ + v4l2_warn(sd, "TVP7002 Read: retry ... %d\n", retry); + retry++; + msleep_interruptible(10); + goto try_read; + } + } + + return error; +} + +/* + * tvp7002_write() - Write a value to a register in TVP5146/47 + * @sd: ptr to v4l2_subdev struct + * @addr: TVP5146/47 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) +{ + int error; + int retry = 0; + struct i2c_client *c = v4l2_get_subdevdata(sd); + +write_again: + error = i2c_smbus_write_byte_data(c, addr, value); + if (error) { + if (retry <= I2C_RETRY_COUNT) { + v4l2_warn(sd, "TVP7002 Write: retry ... %d\n", retry); + retry++; + msleep_interruptible(10); + goto write_again; + } + } + + return error; +} + +/* + * dump_reg_range() - Dump information from TVP7002 registers + * @sd: ptr to v4l2_subdev struct + * @init: TVP7002 start address + * @init: TVP7002 end address + * @nline: register values per line + * + * 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 == -1) + v4l2_err(sd, "tvp7002: reg 0x%02x unreadable\n", i); + else + v4l2_info(sd, "tvp7002: @0x%02x = %02x\n", i, result); + + init++; + i++; + } + printk("\n"); +} + +/* + * tvp7002_log_status() - Print information about register settings + * @sd: ptr to v4l2_subdev struct + * + * Log regsiter values of a TVP7002 decoder device. + * Returns zero or -EINVAL if read operation fails. + */ +static int tvp7002_log_status(struct v4l2_subdev *sd) +{ + int error, rres; + + rres = tvp7002_read(sd, TVP7002_CHIP_REV); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", TVP7002_CHIP_REV); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Chip revision number = 0x%02x\n", + TVP7002_CHIP_REV); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_FDBK_DIV_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: H-PLL feedback div LSB = 0x%02x\n", + TVP7002_HPLL_FDBK_DIV_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_FDBK_DIV_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: H-PLL feedback div MSB = 0x%02x\n", + TVP7002_HPLL_FDBK_DIV_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_CRTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", TVP7002_HPLL_CRTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VCO frequency range selector = 0x%02x\n", + TVP7002_HPLL_CRTL); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_PHASE_SEL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_PHASE_SEL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: ADC sampling clk phase select = 0x%02x\n", + TVP7002_HPLL_PHASE_SEL); + } + + rres = tvp7002_read(sd, TVP7002_CLAMP_START); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_CLAMP_START); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Clamp start = 0x%02x\n", + TVP7002_CLAMP_START); + } + + rres = tvp7002_read(sd, TVP7002_CLAMP_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", TVP7002_CLAMP_W); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Clamp width = 0x%02x\n", TVP7002_CLAMP_W); + } + + rres = tvp7002_read(sd, TVP7002_HSYNC_OUT_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HSYNC_OUT_W); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: HSYNC output width = 0x%02x\n", + TVP7002_HSYNC_OUT_W); + } + + rres = tvp7002_read(sd, TVP7002_B_FINE_GAIN); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_B_FINE_GAIN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain for B ch = 0x%02x\n", + TVP7002_B_FINE_GAIN); + } + + rres = tvp7002_read(sd, TVP7002_G_FINE_GAIN); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_G_FINE_GAIN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain for G ch = 0x%02x\n", + TVP7002_G_FINE_GAIN); + } + + rres = tvp7002_read(sd, TVP7002_R_FINE_GAIN); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_FINE_GAIN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain for R ch = 0x%02x\n", + TVP7002_R_FINE_GAIN); + } + + rres = tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_B_FINE_OFF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain off B ch = 0x%02x\n", + TVP7002_B_FINE_OFF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_G_FINE_OFF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain off G ch = 0x%02x\n", + TVP7002_G_FINE_OFF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_FINE_OFF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Digital fine grain off R ch = 0x%02x\n", + TVP7002_R_FINE_OFF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_FINE_OFF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Dig fine grain off R ch LSBs = 0x%02x\n", + TVP7002_FINE_OFF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_SYNC_CTL_1); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SYNC_CTL_1); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: SYNC control 1 = 0x%02x\n", + TVP7002_SYNC_CTL_1); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_AND_CLAMP_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_AND_CLAMP_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: H-PLL and clamp control = 0x%02x\n", + TVP7002_HPLL_AND_CLAMP_CTL); + } + + rres = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SYNC_ON_G_THRS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Sync-On-Green threshold = 0x%02x\n", + TVP7002_SYNC_ON_G_THRS); + } + + rres = tvp7002_read(sd, TVP7002_SYNC_SEPARATOR_THRS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SYNC_SEPARATOR_THRS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Sync separator threshold = 0x%02x\n", + TVP7002_SYNC_SEPARATOR_THRS); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_PRE_COAST); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_PRE_COAST); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: H-PLL pre-coast = 0x%02x\n", + TVP7002_HPLL_PRE_COAST); + } + + rres = tvp7002_read(sd, TVP7002_HPLL_POST_COAST); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HPLL_POST_COAST); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: H-PLL post-coast = 0x%02x\n", + TVP7002_HPLL_POST_COAST); + } + + rres = tvp7002_read(sd, TVP7002_SYNC_DETECT_STAT); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SYNC_DETECT_STAT); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Sync detect status = 0x%02x\n", + TVP7002_SYNC_DETECT_STAT); + } + + rres = tvp7002_read(sd, TVP7002_OUT_FORMATTER); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_OUT_FORMATTER); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Output formatter = 0x%02x\n", + TVP7002_OUT_FORMATTER); + } + + rres = tvp7002_read(sd, TVP7002_MISC_CTL_1); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MISC_CTL_1); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Miscelaneous control 1 = 0x%02x\n", + TVP7002_MISC_CTL_1); + } + + rres = tvp7002_read(sd, TVP7002_MISC_CTL_2); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MISC_CTL_2); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Miscelaneous control 2 = 0x%02x\n", + TVP7002_MISC_CTL_2); + } + + rres = tvp7002_read(sd, TVP7002_MISC_CTL_3); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MISC_CTL_3); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Miscelaneous control 3 = 0x%02x\n", + TVP7002_MISC_CTL_3); + } + + rres = tvp7002_read(sd, TVP7002_MISC_CTL_3); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MISC_CTL_3); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Miscelaneous control 3 = 0x%02x\n", + TVP7002_MISC_CTL_3); + } + + rres = tvp7002_read(sd, TVP7002_IN_MUX_SEL_1); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_IN_MUX_SEL_1); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Input Mux Selector 1 = 0x%02x\n", + TVP7002_IN_MUX_SEL_1); + } + + rres = tvp7002_read(sd, TVP7002_IN_MUX_SEL_2); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_IN_MUX_SEL_2); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Input Mux Selector 1 = 0x%02x\n", + TVP7002_IN_MUX_SEL_2); + } + + rres = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_B_AND_G_COARSE_GAIN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: B and G coarse gain = 0x%02x\n", + TVP7002_B_AND_G_COARSE_GAIN); + } + + rres = tvp7002_read(sd, TVP7002_R_COARSE_GAIN); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_COARSE_GAIN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: R coarse gain = 0x%02x\n", + TVP7002_R_COARSE_GAIN); + } + + rres = tvp7002_read(sd, TVP7002_B_COARSE_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_B_COARSE_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Coarse offset for B ch = 0x%02x\n", + TVP7002_B_COARSE_OFF); + } + + rres = tvp7002_read(sd, TVP7002_G_COARSE_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_G_COARSE_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Coarse offset for G ch = 0x%02x\n", + TVP7002_G_COARSE_OFF); + } + + rres = tvp7002_read(sd, TVP7002_R_COARSE_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_COARSE_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Coarse offset for R ch = 0x%02x\n", + TVP7002_R_COARSE_OFF); + } + + rres = tvp7002_read(sd, TVP7002_R_COARSE_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_COARSE_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Coarse offset for R ch = 0x%02x\n", + TVP7002_R_COARSE_OFF); + } + + rres = tvp7002_read(sd, TVP7002_HSOUT_OUT_START); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HSOUT_OUT_START); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: HSYNC lead edge out start = 0x%02x\n", + TVP7002_HSOUT_OUT_START); + } + + rres = tvp7002_read(sd, TVP7002_MISC_CTL_4); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MISC_CTL_4); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Miscelaneous control 4 = 0x%02x\n", + TVP7002_MISC_CTL_4); + } + + rres = tvp7002_read(sd, TVP7002_B_DGTL_ALC_OUT_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_B_DGTL_ALC_OUT_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Filt ALC out for B ch LSBs = 0x%02x\n", + TVP7002_B_DGTL_ALC_OUT_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_G_DGTL_ALC_OUT_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_G_DGTL_ALC_OUT_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Filt ALC out for G ch LSBs = 0x%02x\n", + TVP7002_G_DGTL_ALC_OUT_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_R_DGTL_ALC_OUT_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_R_DGTL_ALC_OUT_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Filt ALC out for R ch LSBs = 0x%02x\n", + TVP7002_R_DGTL_ALC_OUT_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_ENABLE); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AUTO_LVL_CTL_ENABLE); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Auto level control enable = 0x%02x\n", + TVP7002_AUTO_LVL_CTL_ENABLE); + } + + rres = tvp7002_read(sd, TVP7002_DGTL_ALC_OUT_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_DGTL_ALC_OUT_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Filt ALC out RGB chs MSB = 0x%02x\n", + TVP7002_DGTL_ALC_OUT_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_AUTO_LVL_CTL_FILTER); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AUTO_LVL_CTL_FILTER); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Auto level control filter = 0x%02x\n", + TVP7002_AUTO_LVL_CTL_FILTER); + } + + rres = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_FINE_CLAMP_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Fine clamp control = 0x%02x\n", + TVP7002_FINE_CLAMP_CTL); + } + + rres = tvp7002_read(sd, TVP7002_PWR_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_PWR_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Power control = 0x%02x\n", + TVP7002_PWR_CTL); + } + + rres = tvp7002_read(sd, TVP7002_ADC_SETUP); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_ADC_SETUP); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: ADC setup = 0x%02x\n", + TVP7002_ADC_SETUP); + } + + rres = tvp7002_read(sd, TVP7002_COARSE_CLAMP_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_COARSE_CLAMP_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Coarse clamp control = 0x%02x\n", + TVP7002_COARSE_CLAMP_CTL); + } + + rres = tvp7002_read(sd, TVP7002_SOG_CLAMP); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SOG_CLAMP); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Sync-On-Green clamp = 0x%02x\n", + TVP7002_SOG_CLAMP); + } + + rres = tvp7002_read(sd, TVP7002_RGB_COARSE_CLAMP_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_RGB_COARSE_CLAMP_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: RGB coarse clamp control = 0x%02x\n", + TVP7002_RGB_COARSE_CLAMP_CTL); + } + + rres = tvp7002_read(sd, TVP7002_SOG_COARSE_CLAMP_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SOG_COARSE_CLAMP_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: SOG coarse clamp control = 0x%02x\n", + TVP7002_SOG_COARSE_CLAMP_CTL); + } + + rres = tvp7002_read(sd, TVP7002_ALC_PLACEMENT); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_ALC_PLACEMENT); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: ALC placement = 0x%02x\n", + TVP7002_ALC_PLACEMENT); + } + + rres = tvp7002_read(sd, TVP7002_MVIS_STRIPPER_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_MVIS_STRIPPER_W); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Macrovision stripper width = 0x%02x\n", + TVP7002_VSYNC_ALGN); + } + + rres = tvp7002_read(sd, TVP7002_MVIS_STRIPPER_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VSYNC_ALGN); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VSYNC alignment = 0x%02x\n", + TVP7002_VSYNC_ALGN); + } + + rres = tvp7002_read(sd, TVP7002_SYNC_BYPASS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_SYNC_BYPASS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Sync bypass = 0x%02x\n", + TVP7002_SYNC_BYPASS); + } + + rres = tvp7002_read(sd, TVP7002_L_FRAME_STAT_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_L_FRAME_STAT_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Lines p Frame status LSBs = 0x%02x\n", + TVP7002_L_FRAME_STAT_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_L_FRAME_STAT_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_L_FRAME_STAT_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Lines p Frame status MSBs = 0x%02x\n", + TVP7002_L_FRAME_STAT_MSBS); + } + + + rres = tvp7002_read(sd, TVP7002_CLK_L_STAT_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_CLK_L_STAT_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Clks p line status LSBs = 0x%02x\n", + TVP7002_CLK_L_STAT_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_CLK_L_STAT_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_CLK_L_STAT_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Clks p line status MSBs = 0x%02x\n", + TVP7002_CLK_L_STAT_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_HSYNC_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_HSYNC_W); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: HSYNC width = 0x%02x\n", + TVP7002_HSYNC_W); + } + + rres = tvp7002_read(sd, TVP7002_VSYNC_W); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VSYNC_W); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VSYNC width = 0x%02x\n", + TVP7002_VSYNC_W); + } + + rres = tvp7002_read(sd, TVP7002_L_LENGTH_TOL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_L_LENGTH_TOL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Line length tolerance = 0x%02x\n", + TVP7002_L_LENGTH_TOL); + } + + rres = tvp7002_read(sd, TVP7002_VIDEO_BWTH_CTL); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VIDEO_BWTH_CTL); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: Video bandwidth control = 0x%02x\n", + TVP7002_VIDEO_BWTH_CTL); + } + + rres = tvp7002_read(sd, TVP7002_AVID_START_PIXEL_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AVID_START_PIXEL_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: AVID start pixel LSBs = 0x%02x\n", + TVP7002_AVID_START_PIXEL_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_AVID_START_PIXEL_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AVID_START_PIXEL_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: AVID start pixel MSBs = 0x%02x\n", + TVP7002_AVID_START_PIXEL_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AVID_STOP_PIXEL_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: AVID stop pixel LSBs = 0x%02x\n", + TVP7002_AVID_STOP_PIXEL_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_AVID_STOP_PIXEL_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_AVID_STOP_PIXEL_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: AVID stop pixel MSBs = 0x%02x\n", + TVP7002_AVID_STOP_PIXEL_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_VBLK_F_0_START_L_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VBLK_F_0_START_L_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VBLK start line offset 0 = 0x%02x\n", + TVP7002_VBLK_F_0_START_L_OFF); + } + + rres = tvp7002_read(sd, TVP7002_VBLK_F_1_START_L_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VBLK_F_1_START_L_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VBLK start line offset 1 = 0x%02x\n", + TVP7002_VBLK_F_1_START_L_OFF); + } + + rres = tvp7002_read(sd, TVP7002_VBLK_F_0_DURATION); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VBLK_F_0_DURATION); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VBLK duration 0 = 0x%02x\n", + TVP7002_VBLK_F_0_DURATION); + } + + rres = tvp7002_read(sd, TVP7002_VBLK_F_1_DURATION); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_VBLK_F_1_DURATION); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: VBLK duration 1 = 0x%02x\n", + TVP7002_VBLK_F_1_DURATION); + } + + rres = tvp7002_read(sd, TVP7002_FBIT_F_0_START_L_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_FBIT_F_0_START_L_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: F-bit start line offset 0 = 0x%02x\n", + TVP7002_FBIT_F_0_START_L_OFF); + } + + rres = tvp7002_read(sd, TVP7002_FBIT_F_1_START_L_OFF); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_FBIT_F_1_START_L_OFF); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: F-bit start line offset 1 = 0x%02x\n", + TVP7002_FBIT_F_1_START_L_OFF); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_G_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y G LSBs = 0x%02x\n", + TVP7002_YUV_Y_G_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_G_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_G_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y G MSBs = 0x%02x\n", + TVP7002_YUV_Y_G_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_B_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y B LSBs = 0x%02x\n", + TVP7002_YUV_Y_B_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_B_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_B_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y B MSBs = 0x%02x\n", + TVP7002_YUV_Y_B_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_R_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y R LSBs = 0x%02x\n", + TVP7002_YUV_Y_R_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_Y_R_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_Y_R_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV Y R MSBs = 0x%02x\n", + TVP7002_YUV_Y_R_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_G_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_G_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U G LSBs = 0x%02x\n", + TVP7002_YUV_U_G_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_G_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_G_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U G MSBs = 0x%02x\n", + TVP7002_YUV_U_G_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_B_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_B_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U B LSBs = 0x%02x\n", + TVP7002_YUV_U_B_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_B_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_B_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U B MSBs = 0x%02x\n", + TVP7002_YUV_U_B_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_R_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_R_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U R LSBs = 0x%02x\n", + TVP7002_YUV_U_R_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_U_R_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_U_R_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV U R MSBs = 0x%02x\n", + TVP7002_YUV_U_R_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_G_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_G_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V G LSBs = 0x%02x\n", + TVP7002_YUV_V_G_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_G_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_G_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V G MSBs = 0x%02x\n", + TVP7002_YUV_V_G_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_B_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_B_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V B LSBs = 0x%02x\n", + TVP7002_YUV_V_B_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_B_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_B_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V B MSBs = 0x%02x\n", + TVP7002_YUV_V_B_COEF_MSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_R_COEF_LSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_R_COEF_LSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V R LSBs = 0x%02x\n", + TVP7002_YUV_V_R_COEF_LSBS); + } + + rres = tvp7002_read(sd, TVP7002_YUV_V_R_COEF_MSBS); + if (rres == -1){ + v4l2_err(sd, "tvp7002: error reading 0x%02x\n", + TVP7002_YUV_V_R_COEF_MSBS); + error = -EINVAL; + goto found_error; + } + else { + v4l2_info(sd, "tvp7002: YUV V R MSBs = 0x%02x\n", + TVP7002_YUV_V_R_COEF_MSBS); + } + + error = 0; + +found_error: + return error; +} + +/* + * 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 == -1) + return -EINVAL; + else + 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 == -1){ + error = -EINVAL; + goto found_error; + } + else { + regs++; + } + } + /* Initialize the last (undefined) registers */ + for (i = 0x5c; i <= 0xff; i++){ + error = tvp7002_write(sd, i, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + else { + regs++; + } + } + + error = 0; + +found_error: + return error; +} + +/* + * 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, "tvp7002: sf out of range\n"); + error = -ERANGE; + goto found_error; + } + + /* Print specific information about current format */ + v4l2_info(sd, "tvp7002: Setting standard display format...\n"); + v4l2_info(sd, "tvp7002: 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 == -1){ + error = -EINVAL; + goto found_error; + } + + error = tvp7002_write(sd, TVP7002_HPLL_FDBK_DIV_LSBS, + tvp7002_resolutions[sdf].reg02); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + + error = tvp7002_write(sd, TVP7002_HPLL_CRTL, tvp7002_resolutions[sdf].reg03); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + + error = tvp7002_write(sd, TVP7002_HPLL_PHASE_SEL, + tvp7002_resolutions[sdf].reg04); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + + /* Set SD/HD mode registers */ + + if (sdf < TVP7002_STD_720P_60){ + error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x06); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x10); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x03); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x03); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0x17); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + if (sdf < TVP7002_STD_480P){ + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x0c); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x24); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + else { + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x0a); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x12); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x08); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x18); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + else { + error = tvp7002_write(sd, TVP7002_CLAMP_START, 0x32); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_CLAMP_W, 0x20); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_HPLL_PRE_COAST, 0x01); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_HPLL_POST_COAST, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_2, 0xc7); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + if(sdf < TVP7002_STD_1080I_60){ + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x35); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + else { + error = tvp7002_write(sd, TVP7002_HSOUT_OUT_START, 0x39); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_4, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_ALC_PLACEMENT, 0x5a); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + if(sdf < TVP7002_STD_1080P_60){ + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x07); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + else { + error = tvp7002_write(sd, TVP7002_MVIS_STRIPPER_W, 0x03); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + } + if (sdf < TVP7002_STD_1080P_60){ + error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x50); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x0f); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + } + else { + error = tvp7002_write(sd, TVP7002_ADC_SETUP, 0x80); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_VIDEO_BWTH_CTL, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_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 == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_SYNC_SEPARATOR_THRS, 0x40); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, 0x01); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_IN_MUX_SEL_1, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_VSYNC_ALGN, 0x00); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + error = tvp7002_write(sd, TVP7002_L_LENGTH_TOL, 0x06); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + + error = 0; + +found_error: + 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){ + int 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 == -1 || reg02 == -1 || reg03 == -1){ + error = -1; + goto found_error; + } + + switch(reg01){ + case 0x35: + if (reg02 == 0xa0) + error = V4L2_STD_480I_60; + else + error = V4L2_STD_576I_50; + case 0x36: + if (reg02 == 0xa0) + error = V4L2_STD_480P_60; + else + error = V4L2_STD_576P_50; + case 0x67: + error = V4L2_STD_720P_60; + case 0x7b: + error = V4L2_STD_720P_50; + case 0x89: + if (reg03 == 0x98) + error = V4L2_STD_1080I_60; + else + error = V4L2_STD_1080P_60; + case 0xa5: + if (reg03 == 0x90) + error = V4L2_STD_1080I_50; + else + error = V4L2_STD_1080P_50; + default: + error = -1; + } + +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, lock_mask; + + if (std_id == NULL) + return -EINVAL; + + /* get the current standard */ + current_std = tvp7002_get_video_mode(sd); + if (current_std == -1) + return -EINVAL; + + /* 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: %s", decoder->video_mode); + return 0; +} + +/** + * 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 res; + int tmp; + + v4l2_info(sd, "tvp7002: g_ctrl called\n"); + + switch (ctrl->id) { + case V4L2_CID_TVP7002_COARSE_GAIN_R: + res = tvp7002_read(sd, TVP7002_R_COARSE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x0F; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_COARSE_GAIN_G: + res = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res & 0xF0) >> 4; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_COARSE_GAIN_B: + res = tvp7002_read(sd, TVP7002_B_AND_G_COARSE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x0F; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_FINE_GAIN_R: + res = tvp7002_read(sd, TVP7002_R_FINE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0xFF; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_FINE_GAIN_G: + res = tvp7002_read(sd, TVP7002_G_FINE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0xFF; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_FINE_GAIN_B: + res = tvp7002_read(sd, TVP7002_B_FINE_GAIN); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0xFF; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_B_CLAMP: + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res >> 2) & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_G_CLAMP: + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res >> 1) & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_R_CLAMP: + res = tvp7002_read(sd, TVP7002_SYNC_ON_G_THRS); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_CLAMP_OFF_EN: + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res >> 7) & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_FCTCA: + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (((res >> 3) & 0x03) == 0x03) ? 1 : 0; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_F_CLAMP_GB: + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res >> 1) & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_F_CLAMP_R: + res = tvp7002_read(sd, TVP7002_FINE_CLAMP_CTL); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x01; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_CLAMP_START: + res = tvp7002_read(sd, TVP7002_CLAMP_START); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0xff; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_CLAMP_W: + res = tvp7002_read(sd, TVP7002_CLAMP_W); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0xff; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_B_COARSE_OFF: + res = tvp7002_read(sd, TVP7002_B_COARSE_OFF); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x3f; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_G_COARSE_OFF: + res = tvp7002_read(sd, TVP7002_G_COARSE_OFF); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x3f; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_R_COARSE_OFF: + res = tvp7002_read(sd, TVP7002_R_COARSE_OFF); + if (res == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = res & 0x3f; + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_B_FINE_OFF: + res = tvp7002_read(sd, TVP7002_B_FINE_OFF_MSBS); + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); + if (res == -1 || tmp == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res << 2) | (tmp & 0x03); + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_G_FINE_OFF: + res = tvp7002_read(sd, TVP7002_G_FINE_OFF_MSBS); + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); + if (res == -1 || tmp == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res << 2) | ((tmp >> 2) & 0x03); + res = ctrl->value; + } + break; + case V4L2_CID_TVP7002_R_FINE_OFF: + res = tvp7002_read(sd, TVP7002_R_FINE_OFF_MSBS); + tmp = tvp7002_read(sd, TVP7002_FINE_OFF_LSBS); + if (res == -1 || tmp == -1){ + res = -EINVAL; + goto found_error; + } + else { + ctrl->value = (res << 2) | ((tmp >> 4) & 0x03); + res = ctrl->value; + } + break; + default: + res = -EINVAL; + break; + } + +found_error: + return res; +} + +/* + * 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 error; + 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_err(sd, "s_ctrl: id=%d, value=%d\n", ctrl->id, + ctrl->value); + break; + } + + switch (ctrl->id) { + case V4L2_CID_TVP7002_COARSE_GAIN_R: + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, + ctrl->value & 0xff); + break; + case V4L2_CID_TVP7002_COARSE_GAIN_G: + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, + (ctrl->value << 4) & 0xf0); + break; + case V4L2_CID_TVP7002_COARSE_GAIN_B: + error = tvp7002_write(sd, TVP7002_B_AND_G_COARSE_GAIN, + ctrl->value& 0x0f); + break; + case V4L2_CID_TVP7002_FINE_GAIN_R: + error = tvp7002_write(sd, TVP7002_R_FINE_GAIN, + ctrl->value & 0xff); + break; + case V4L2_CID_TVP7002_FINE_GAIN_G: + error = tvp7002_write(sd, TVP7002_G_FINE_GAIN, + (ctrl->value << 4) & 0xf0); + break; + case V4L2_CID_TVP7002_FINE_GAIN_B: + error = tvp7002_write(sd, TVP7002_B_FINE_GAIN, + ctrl->value& 0x0f); + break; + case V4L2_CID_TVP7002_B_CLAMP: + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, + (ctrl->value << 2) & 0x04); + break; + case V4L2_CID_TVP7002_G_CLAMP: + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, + (ctrl->value << 1) & 0x02); + break; + case V4L2_CID_TVP7002_R_CLAMP: + error = tvp7002_write(sd, TVP7002_SYNC_ON_G_THRS, + ctrl->value & 0x01); + break; + case V4L2_CID_TVP7002_CLAMP_OFF_EN: + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, + (ctrl->value << 7) & 0x80); + break; + case V4L2_CID_TVP7002_FCTCA: + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, + ((ctrl->value == 0 ? 0x00 : 0x03) << 3) & 0x0c); + break; + case V4L2_CID_TVP7002_F_CLAMP_GB: + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, + (ctrl->value << 1) & 0x02); + break; + case V4L2_CID_TVP7002_F_CLAMP_R: + error = tvp7002_write(sd, TVP7002_FINE_CLAMP_CTL, + ctrl->value & 0x01); + break; + case V4L2_CID_TVP7002_CLAMP_START: + error = tvp7002_write(sd, TVP7002_CLAMP_START, + ctrl->value & 0xff); + break; + case V4L2_CID_TVP7002_CLAMP_W: + error = tvp7002_write(sd, TVP7002_CLAMP_W, ctrl->value & 0xff); + break; + case V4L2_CID_TVP7002_B_COARSE_OFF: + error = tvp7002_write(sd, TVP7002_B_COARSE_OFF, + ctrl->value & 0x3f); + break; + case V4L2_CID_TVP7002_G_COARSE_OFF: + error = tvp7002_write(sd, TVP7002_G_COARSE_OFF, + ctrl->value & 0x3f); + break; + case V4L2_CID_TVP7002_R_COARSE_OFF: + error = tvp7002_write(sd, TVP7002_R_COARSE_OFF, + ctrl->value & 0x3f); + break; + case V4L2_CID_TVP7002_B_FINE_OFF: + error = tvp7002_write(sd, TVP7002_B_FINE_OFF_MSBS, + (ctrl->value & 0xff) >> 2) | + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, + ctrl->value & 0x03); + break; + case V4L2_CID_TVP7002_G_FINE_OFF: + error = tvp7002_write(sd, TVP7002_G_FINE_OFF_MSBS, + (ctrl->value & 0xff) >> 2) | + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, + (ctrl->value & 0x03) << 2); + break; + case V4L2_CID_TVP7002_R_FINE_OFF: + error = tvp7002_write(sd, TVP7002_R_FINE_OFF_MSBS, + (ctrl->value & 0xff) >> 2) | + tvp7002_write(sd, TVP7002_FINE_OFF_LSBS, + (ctrl->value & 0x03) << 4); + break; + default: + error = -1; + break; + } + + if (error == -1) + 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) +{ + int error; + + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)){ + error = -EINVAL; + goto found_error; + } + if (!capable(CAP_SYS_ADMIN)){ + error = -EPERM; + goto found_error; + } + + reg->val = tvp7002_read(sd, reg->reg & 0xff); + reg->size = 1; + + if (reg->val == -1) + error = -EINVAL; + else + error = 0; +found_error: + 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)){ + error = -EINVAL; + goto found_error; + } + if (!capable(CAP_SYS_ADMIN)){ + error = -EPERM; + goto found_error; + } + + wres = tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); + + if (wres == -1) + error = -EINVAL; + else + error = 0; + +found_error: + 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; + + v4l2_info(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)); + error = 0; + } + + error = -EINVAL; + + 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; + + switch (enable) { + case 0: + { + /* 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; + break; + } + case 1: + { + /* 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 == -1) { + v4l2_err(sd, "Unable to initialize\n"); + err = -EINVAL; + } + /* Detect if not already detected */ + err = tvp7002_read(sd, TVP7002_CHIP_REV); + if (err == -1) { + v4l2_err(sd, "Unable to detect decoder\n"); + err = -EINVAL; + } + decoder->streaming = enable; + break; + } + default: + { + err = -ENODEV; + break; + } + } + + 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 error; + int polarity; + + error = tvp7002_read(sd, TVP7002_CHIP_REV); + if (error == -1){ + error = -EINVAL; + goto found_error; + } + + if (error == 0x02) + v4l2_info(sd, "tvp7002: rev. %02x detected.\n", error); + + else { + v4l2_info(sd, "tvp7002: unknown revision detected.\n"); + v4l2_info(sd, "tvp7002: 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 == -1){ + error = -EINVAL; + goto found_error; + } + + /* Initializes TVP7002 to its default values */ + error = tvp7002_write_inittab(sd, tvp7002_init_default); + if (error == -1){ + 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) +{ + int error; + int polarity; + 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)){ + error = -EIO; + } + + core = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); + + if (!core) { + error = -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 == -1){ + error = -EINVAL; + goto found_error; + } + + /* Set video mode */ + core->video_mode = V4L2_STD_480P_60; + + if (debug > 1) + error = tvp7002_log_status(sd); + else + error = 0; + +found_error: + 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 v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tvp7002", + .probe = tvp7002_probe, + .remove = tvp7002_remove, + .id_table = tvp7002_id, +};