Santiago, What is your plan to resolve this?
Murali Karicheri Software Design Engineer Texas Instruments Inc. Germantown, MD 20874 new phone: 301-407-9583 Old Phone : 301-515-3736 (will be deprecated) email: [email protected] >-----Original Message----- >From: Santiago Nunez-Corrales [mailto:[email protected]] >Sent: Friday, September 04, 2009 4:21 PM >To: Karicheri, Muralidharan >Cc: Narnakaje, Snehaprabha; [email protected]; >[email protected]; [email protected]; >[email protected] >Subject: Re: [PATCH 5/6 v4] Updated TVP7002 driver for DM365 > >Murali, > > >Changing the querystd code. I found various errors w.r.t. LPS 2.10 from >what I was doing in my code. I am reading the wrong register, which is >causing the code to return from the call incorrectly. > >Regards, > >Karicheri, Muralidharan wrote: >> Santiago, >> >> Also modify the querystd() by re-using the code from LSP 2.10 as I have >asked very beginning. This logic is tested well and works. >> >> Murali Karicheri >> Software Design Engineer >> Texas Instruments Inc. >> Germantown, MD 20874 >> new phone: 301-407-9583 >> Old Phone : 301-515-3736 (will be deprecated) >> email: [email protected] >> >> >>> -----Original Message----- >>> From: Narnakaje, Snehaprabha >>> Sent: Friday, September 04, 2009 11:18 AM >>> To: [email protected]; davinci-linux-open- >>> [email protected] >>> Cc: Karicheri, Muralidharan; [email protected]; >>> [email protected]; [email protected] >>> Subject: RE: [PATCH 5/6 v4] Updated TVP7002 driver for DM365 >>> >>> Santiago, >>> >>> >>>> -----Original Message----- >>>> From: [email protected] [mailto:[email protected]] >>>> Sent: Thursday, September 03, 2009 6:53 PM >>>> To: [email protected] >>>> Cc: Karicheri, Muralidharan; [email protected]; >>>> [email protected]; [email protected]; Narnakaje, >>>> Snehaprabha; Santiago Nunez-Corrales >>>> Subject: [PATCH 5/6 v4] Updated TVP7002 driver for DM365 >>>> >>>> From: Santiago Nunez-Corrales <[email protected]> >>>> >>>> This patch provides the implementation of the TVP7002 decoder >>>> driver for DM365. Implemented revisions by Vaibhav Hiremath >>>> and Hans Verkuil. Removed most of controls, cleared up logic, >>>> cleaned up code. Tested on DM365 TI EVM. >>>> >>>> Signed-off-by: Santiago Nunez-Corrales <[email protected]> >>>> --- >>>> drivers/media/video/tvp7002.c | 1464 >>>> >>> [...] >>> >>> >>>> + >>>> +/* >>>> + * 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 reg01, reg02, reg03; >>>> + >>>> + reg01 = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_MSBS); >>>> + reg02 = tvp7002_read(sd, TVP7002_HPLL_FDBK_DIV_LSBS); >>>> + reg03 = tvp7002_read(sd, TVP7002_HPLL_CRTL); >>>> + >>>> + if (reg01 < 0 || reg02 < 0 || reg03 < 0) >>>> + return V4L2_STD_UNKNOWN; >>>> + >>>> + switch (reg01) { >>>> + case 0x35: >>>> + if (reg02 == 0xa0) >>>> + return V4L2_STD_NTSC; >>>> + else >>>> + return V4L2_STD_PAL; >>>> + case 0x36: >>>> + if (reg02 == 0xa0) >>>> + return V4L2_STD_525P_60; >>>> + else >>>> + return V4L2_STD_625P_50; >>>> + case 0x67: >>>> + return V4L2_STD_720P_60; >>>> + case 0x7b: >>>> + return V4L2_STD_720P_50; >>>> + case 0x89: >>>> + if (reg03 == 0x98) >>>> + return V4L2_STD_1080I_60; >>>> + else >>>> + return V4L2_STD_1080P_60; >>>> + break; >>>> + case 0xa5: >>>> + if (reg03 == 0x90) >>>> + return V4L2_STD_1080I_50; >>>> + else >>>> + return V4L2_STD_1080P_50; >>>> + default: >>>> + return V4L2_STD_UNKNOWN; >>>> + } >>>> +} >>>> + >>>> +/* >>>> + * 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) >>>> +{ >>>> + v4l2_std_id current_std; >>>> + u8 sync_lock_status; >>>> + int res; >>>> + >>>> + if (std_id == NULL) >>>> + return -EINVAL; >>>> + >>>> + /* get the current standard */ >>>> + res = tvp7002_get_video_mode(sd); >>>> + if (res == V4L2_STD_UNKNOWN) >>>> + return -EINVAL; >>>> >>> There seems to be a bug here - You will mostly get V4L2_STD_UNKNOWN for >HD >>> resolutions. The tvp7002_get_video_mode() API returns v4l2_std_id (which >is >>> long long - 64 bits), but you are storing the return value in "int res". >>> You should change it to - >>> >>> v4l2_std_id res; >>> >>> Note that I am trying to integrate your driver with VPIF capture on >DM6467 >>> and thus running into issues like this. It would be good to know - >whether >>> you have tested the TVP7002 driver on DM365 using a capture application. >>> >>> Thanks >>> Sneha >>> >>> >>>> + current_std = res; >>>> + >>>> + /* check whether signal is locked */ >>>> + sync_lock_status = tvp7002_read(sd, TVP7002_SYNC_DETECT_STAT); >>>> + >>>> + if (0x02 != (sync_lock_status & 0xff)) >>>> + return -EINVAL; /* No input detected */ >>>> + >>>> + *std_id = current_std; >>>> + >>>> + v4l2_dbg(1, debug, sd, "Current STD: %d %d @ %d Hz\n", >>>> + tvp7002_resolutions[tvp7002_from_std(current_std)].hres, >>>> + tvp7002_resolutions[tvp7002_from_std(current_std)].vres, >>>> + tvp7002_resolutions[tvp7002_from_std(current_std)].frate); >>>> + return 0; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_try_fmt_cap() - V4L2 decoder interface handler for try_fmt >>>> + * @sd: pointer to standard V4L2 sub-device structure >>>> + * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure >>>> + * >>>> + * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. >This >>>> + * ioctl is used to negotiate the image capture size and pixel format >>>> + * without actually making it take effect. >>>> + */ >>>> +static int tvp7002_try_fmt_cap(struct v4l2_subdev *sd, struct >>>> >>> v4l2_format >>> >>>> *f) >>>> +{ >>>> + struct v4l2_pix_format *pix; >>>> + v4l2_std_id current_std; >>>> + int res; >>>> + >>>> + if (f == NULL) >>>> + return -EINVAL; >>>> + >>>> + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >>>> + /* only capture is supported */ >>>> + return -EINVAL; >>>> + >>>> + pix = &f->fmt.pix; >>>> + >>>> + /* Calculate height and width based on current standard */ >>>> + res = tvp7002_get_video_mode(sd); >>>> + if (res < 0) >>>> + return -EINVAL; >>>> + current_std = res; >>>> + >>>> + pix->width = NUM_ACTIVE_PIXELS(current_std); >>>> + pix->height = NUM_ACTIVE_LINES(current_std); >>>> + >>>> + pix->pixelformat = V4L2_PIX_FMT_UYVY; >>>> + >>>> + pix->field = V4L2_FIELD_INTERLACED; >>>> + pix->bytesperline = pix->width * 2; >>>> + pix->sizeimage = pix->bytesperline * pix->height; >>>> + pix->colorspace = V4L2_COLORSPACE_REC709; >>>> + pix->priv = 0; >>>> + >>>> + v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - >>>> %d" >>>> + "Width - %d, Height - %d", >>>> + "8-bit UYVY 4:2:2 Format", pix->bytesperline, >>>> + pix->width, pix->height); >>>> + return 0; >>>> +} >>>> + >>>> +/** >>>> + * tvp7002_s_fmt_cap() - V4L2 decoder interface handler for s_fmt >>>> + * @sd: pointer to standard V4L2 sub-device structure >>>> + * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure >>>> + * >>>> + * If the requested format is supported, configures the HW to use that >>>> + * format, returns error code if format not supported or HW can't be >>>> + * correctly configured. >>>> + */ >>>> +static int tvp7002_s_fmt_cap(struct v4l2_subdev *sd, struct >v4l2_format >>>> *f) >>>> +{ >>>> + struct tvp7002 *decoder = to_tvp7002(sd); >>>> + struct v4l2_pix_format *pix; >>>> + int rval; >>>> + >>>> + if (f == NULL) >>>> + return -EINVAL; >>>> + >>>> + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >>>> + /* only capture is supported */ >>>> + return -EINVAL; >>>> + >>>> + pix = &f->fmt.pix; >>>> + rval = tvp7002_try_fmt_cap(sd, f); >>>> + if (rval) >>>> + return rval; >>>> + >>>> + decoder->pix = *pix; >>>> + >>>> + return rval; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_g_fmt() - V4L2 decoder interface handler for tvp7002_g_fmt >>>> + * @sd: pointer to standard V4L2 sub-device structure >>>> + * @f: pointer to standard V4L2 v4l2_format structure >>>> + * >>>> + * Returns the decoder's current pixel format in the v4l2_format >>>> + * parameter. >>>> + */ >>>> +static int tvp7002_g_fmt(struct v4l2_subdev *sd, struct v4l2_format >*f) >>>> +{ >>>> + struct tvp7002 *decoder = to_tvp7002(sd); >>>> + >>>> + if (f == NULL) >>>> + return -EINVAL; >>>> + >>>> + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) >>>> + /* only capture is supported */ >>>> + return -EINVAL; >>>> + >>>> + f->fmt.pix = decoder->pix; >>>> + >>>> + v4l2_dbg(1, debug, 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_dbg(1, debug, sd, "Set video std mode to %llx.\n", std); >>>> + >>>> + return tvp7002_set_video_mode(sd, vmd); >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_g_ctrl() - Get a control >>>> + * @sd: ptr to v4l2_subdev struct >>>> + * @ctrl: ptr to v4l2_control struct >>>> + * >>>> + * Get a control for a TVP7002 decoder device. >>>> + * Returns zero when successful or -EINVAL if register access fails. >>>> + */ >>>> +static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control >>>> *ctrl) >>>> +{ >>>> + int rval, gval, bval; >>>> + int res; >>>> + >>>> + v4l2_info(sd, "g_ctrl called\n"); >>>> + >>>> + switch (ctrl->id) { >>>> + case V4L2_CID_GAIN: >>>> + rval = tvp7002_read(sd, TVP7002_R_FINE_GAIN); >>>> + gval = tvp7002_read(sd, TVP7002_G_FINE_GAIN); >>>> + bval = tvp7002_read(sd, TVP7002_B_FINE_GAIN); >>>> + >>>> + if (rval < 0 || gval < 0 || bval < 0) { >>>> + res = -1; >>>> + } else if (rval != gval || rval != bval) { >>>> + res = -1; >>>> + } else { >>>> + ctrl->value = rval & 0x0F; >>>> + res = ctrl->value; >>>> + } >>>> + break; >>>> + default: >>>> + res = -1; >>>> + break; >>>> + } >>>> + >>>> + return res < 0 ? res : 0; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_s_ctrl() - Set a control >>>> + * @sd: ptr to v4l2_subdev struct >>>> + * @ctrl: ptr to v4l2_control struct >>>> + * >>>> + * Set a control in TVP7002 decoder device. >>>> + * Returns zero when successful or -EINVAL if register access fails. >>>> + */ >>>> +static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control >>>> *ctrl) >>>> +{ >>>> + int rval, gval, bval; >>>> + int error; >>>> + u8 i, n; >>>> + n = ARRAY_SIZE(tvp7002_qctrl); >>>> + >>>> + for (i = 0; i < n; i++) >>>> + if (ctrl->id == tvp7002_qctrl[i].id) >>>> + break; >>>> + >>>> + if (i == n) >>>> + return -EINVAL; >>>> + >>>> + if (ctrl->value < tvp7002_qctrl[i].minimum || >>>> + ctrl->value > tvp7002_qctrl[i].maximum) >>>> + return -ERANGE; >>>> + >>>> + switch (ctrl->id) { >>>> + case V4L2_CID_GAIN: >>>> + rval = tvp7002_write(sd, TVP7002_R_FINE_GAIN, >>>> + ctrl->value & >0xff); >>>> + gval = tvp7002_write(sd, TVP7002_G_FINE_GAIN, >>>> + ctrl->value & >0xff); >>>> + bval = tvp7002_write(sd, TVP7002_B_FINE_GAIN, >>>> + ctrl->value & >0xff); >>>> + if (rval < 0 || gval < 0 || bval < 0) >>>> + error = -1; >>>> + else >>>> + error = rval; >>>> + break; >>>> + default: >>>> + error = -1; >>>> + break; >>>> + } >>>> + >>>> + return error < 0 ? -EINVAL : 0; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_g_register() - Get the value of a register >>>> + * @sd: ptr to v4l2_subdev struct >>>> + * @vreg: ptr to v4l2_dbg_register struct >>>> + * >>>> + * Get the value of a TVP7002 decoder device register. >>>> + * Returns zero when successful, -EINVAL if register read fails or >>>> + * access to I2C client fails, -EPERM if the call is not allowed >>>> + * by diabled CAP_SYS_ADMIN. >>>> + */ >>>> +#ifdef CONFIG_VIDEO_ADV_DEBUG >>>> +static int tvp7002_g_register(struct v4l2_subdev *sd, >>>> + struct v4l2_dbg_register >*reg) >>>> +{ >>>> + struct i2c_client *client = v4l2_get_subdevdata(sd); >>>> + >>>> + if (!v4l2_chip_match_i2c_client(client, ®->match)) >>>> + return -EINVAL; >>>> + if (!capable(CAP_SYS_ADMIN)) >>>> + return -EPERM; >>>> + >>>> + return reg->val < 0 ? -EINVAL : 0; >>>> +} >>>> + >>>> +/* >>>> + * 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 wres; >>>> + struct i2c_client *client = v4l2_get_subdevdata(sd); >>>> + >>>> + if (!v4l2_chip_match_i2c_client(client, ®->match)) >>>> + return -EINVAL; >>>> + if (!capable(CAP_SYS_ADMIN)) >>>> + return -EPERM; >>>> + >>>> + wres = tvp7002_write(sd, reg->reg & 0xff, reg->val & 0xff); >>>> + >>>> + return wres < 0 ? -EINVAL : 0; >>>> +} >>>> +#endif >>>> + >>>> +/* >>>> + * tvp7002_queryctrl() - Query a control >>>> + * @sd: ptr to v4l2_subdev struct >>>> + * @ctrl: ptr to v4l2_queryctrl struct >>>> + * >>>> + * Query a control of a TVP7002 decoder device. >>>> + * Returns zero when successful or -EINVAL if register read fails. >>>> + */ >>>> +static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct >>>> v4l2_queryctrl *qc) >>>> +{ >>>> + int i, error; >>>> + error = -EINVAL; >>>> + >>>> + v4l2_info(sd, "queryctrl called\n"); >>>> + >>>> + for (i = 0; i < ARRAY_SIZE(tvp7002_qctrl); i++) >>>> + if (qc->id && qc->id == tvp7002_qctrl[i].id) { >>>> + v4l2_ctrl_query_fill(qc, tvp7002_qctrl[i].minimum, >>>> + tvp7002_qctrl[i].maximum, >>>> + tvp7002_qctrl[i].step, >>>> + tvp7002_qctrl[i].default_value); >>>> + error = 0; >>>> + break; >>>> + } >>>> + >>>> + return error; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream >>>> + * @sd: pointer to standard V4L2 sub-device structure >>>> + * @enable: streaming enable or disable >>>> + * >>>> + * Sets streaming to enable or disable, if possible. >>>> + */ >>>> +static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) >>>> +{ >>>> + int err = 0; >>>> + struct tvp7002 *decoder = to_tvp7002(sd); >>>> + >>>> + if (decoder->streaming == enable) >>>> + return 0; >>>> + >>>> + if (enable) { >>>> + /* Power Up Sequence */ >>>> + err = tvp7002_write(sd, TVP7002_PWR_CTL, 0x00); >>>> + if (err) { >>>> + v4l2_err(sd, "Unable to turn on decoder\n"); >>>> + err = -EINVAL; >>>> + } >>>> + err = tvp7002_write_inittab(sd, tvp7002_init_default); >>>> + if (err < 0) { >>>> + v4l2_err(sd, "Unable to initialize\n"); >>>> + err = -EINVAL; >>>> + } >>>> + /* Detect if not already detected */ >>>> + err = tvp7002_read(sd, TVP7002_CHIP_REV); >>>> + if (err < 0) { >>>> + v4l2_err(sd, "Unable to detect decoder\n"); >>>> + err = -EINVAL; >>>> + } >>>> + decoder->streaming = enable; >>>> + } else { >>>> + /* Power Down Sequence */ >>>> + err = tvp7002_write(sd, TVP7002_PWR_CTL, 0x40); >>>> + if (err) { >>>> + v4l2_err(sd, "Unable to turn off decoder\n"); >>>> + return err; >>>> + } >>>> + decoder->streaming = enable; >>>> + } >>>> + >>>> + return err; >>>> +} >>>> + >>>> +/* Specific video subsystem operation handlers */ >>>> +static const struct v4l2_subdev_video_ops tvp7002_video_ops = { >>>> + .querystd = tvp7002_querystd, >>>> + .s_stream = tvp7002_s_stream, >>>> + .g_fmt = tvp7002_g_fmt, >>>> +}; >>>> + >>>> +/* V4L2 Operations handlers */ >>>> +static const struct v4l2_subdev_core_ops tvp7002_core_ops = { >>>> + .g_chip_ident = tvp7002_g_chip_ident, >>>> + .log_status = tvp7002_log_status, >>>> + .g_ctrl = tvp7002_g_ctrl, >>>> + .s_ctrl = tvp7002_s_ctrl, >>>> + .queryctrl = tvp7002_queryctrl, >>>> + .s_std = tvp7002_s_std, >>>> +#ifdef CONFIG_VIDEO_ADV_DEBUG >>>> + .g_register = tvp7002_g_register, >>>> + .s_register = tvp7002_s_register, >>>> +#endif >>>> +}; >>>> + >>>> +static const struct v4l2_subdev_ops tvp7002_ops = { >>>> + .core = &tvp7002_core_ops, >>>> + .video = &tvp7002_video_ops, >>>> +}; >>>> + >>>> +/* Default driver settings */ >>>> +static struct tvp7002 tvp7002_dev = { >>>> + .streaming = 0, >>>> + >>>> + .pix = { >>>> + .width = 720, >>>> + .height = 480, >>>> + .pixelformat = V4L2_PIX_FMT_UYVY, >>>> + .field = V4L2_FIELD_INTERLACED, >>>> + .bytesperline = 720 * 2, >>>> + .sizeimage = 720 * 2 * 480, >>>> + .colorspace = V4L2_COLORSPACE_SMPTE170M, >>>> + }, >>>> + >>>> + .video_mode = V4L2_STD_NTSC, >>>> +}; >>>> + >>>> +/* >>>> + * 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) >>>> +{ >>>> + struct tvp7002 *core = to_tvp7002(sd); >>>> + int polarity; >>>> + int error; >>>> + >>>> + error = tvp7002_read(sd, TVP7002_CHIP_REV); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + if (error == 0x02) { >>>> + v4l2_info(sd, "rev. %02x detected.\n", error); >>>> + } else { >>>> + v4l2_info(sd, "unknown revision detected.\n"); >>>> + v4l2_info(sd, "revision number is %02x\n", error); >>>> + } >>>> + >>>> + /* Initializes TVP7002 to its default values */ >>>> + error = tvp7002_write_inittab(sd, tvp7002_init_default); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + /* Set polarity information after registers have been set */ >>>> + polarity = 0x5b | core->pdata->hs_polarity << 5 >>>> + | core->pdata->vs_polarity << 2; >>>> + error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + polarity = 0x0 | core->pdata->fid_polarity << 2 >>>> + | core->pdata->sog_polarity << 1 >>>> + | core->pdata->clk_polarity; >>>> + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> +found_error: >>>> + return error; >>>> +}; >>>> + >>>> +/* >>>> + * tvp7002_probe - Reset a TVP7002 device >>>> + * @sd: ptr to v4l2_subdev struct >>>> + * @ctrl: ptr to i2c_device_id struct >>>> + * >>>> + * Reset the TVP7002 device >>>> + * Returns zero when successful or -EINVAL if register read fails. >>>> + */ >>>> +static int tvp7002_probe(struct i2c_client *c, const struct >>>> >>> i2c_device_id >>> >>>> *id) >>>> +{ >>>> + struct v4l2_subdev *sd; >>>> + struct tvp7002 *core; >>>> + int polarity; >>>> + int error; >>>> + >>>> + /* Check if the adapter supports the needed features */ >>>> + if (!i2c_check_functionality(c->adapter, >>>> + I2C_FUNC_SMBUS_READ_BYTE | >I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) >>>> + return -EIO; >>>> + >>>> + if (!c->dev.platform_data) { >>>> + v4l2_err(c, "No platform data!!\n"); >>>> + return -ENODEV; >>>> + } >>>> + >>>> + core = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); >>>> + >>>> + if (!core) >>>> + return -ENOMEM; >>>> + >>>> + *core = tvp7002_dev; >>>> + sd = &core->sd; >>>> + core->pdata = c->dev.platform_data; >>>> + >>>> + v4l2_i2c_subdev_init(sd, c, &tvp7002_ops); >>>> + v4l_info(c, "tvp7002 found @ 0x%02x (%s)\n", >>>> + c->addr << 1, c->adapter->name); >>>> + >>>> + /* Initializes TVP7002 to its default values */ >>>> + error = tvp7002_write_inittab(sd, tvp7002_init_default); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + /* Set polarity information after registers have been set */ >>>> + polarity = 0x5b | core->pdata->hs_polarity << 5 >>>> + | core->pdata->vs_polarity << 2; >>>> + error = tvp7002_write(sd, TVP7002_SYNC_CTL_1, polarity); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + polarity = 0x0 | core->pdata->fid_polarity << 2 >>>> + | core->pdata->sog_polarity << 1 >>>> + | core->pdata->clk_polarity; >>>> + error = tvp7002_write(sd, TVP7002_MISC_CTL_3, polarity); >>>> + if (error < 0) { >>>> + error = -EINVAL; >>>> + goto found_error; >>>> + } >>>> + >>>> + if (debug > 1) >>>> + tvp7002_log_status(sd); >>>> + >>>> +found_error: >>>> + if (error < 0) >>>> + kfree(core); >>>> + >>>> + return error; >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_remove - Remove TVP7002 device support >>>> + * @c: ptr to i2c_client struct >>>> + * >>>> + * Reset the TVP7002 device >>>> + * Returns zero when successful or -EINVAL if register read fails. >>>> + */ >>>> +static int tvp7002_remove(struct i2c_client *c) >>>> +{ >>>> + struct v4l2_subdev *sd = i2c_get_clientdata(c); >>>> + >>>> + v4l2_dbg(1, debug, sd, "removing tvp7002 adapter" >>>> + "on address 0x%x\n", c->addr << 1); >>>> + >>>> + v4l2_device_unregister_subdev(sd); >>>> + kfree(to_tvp7002(sd)); >>>> + return 0; >>>> +} >>>> + >>>> +/* I2C Device ID table */ >>>> +static const struct i2c_device_id tvp7002_id[] = { >>>> + { "tvp7002", 0 }, >>>> + { } >>>> +}; >>>> +MODULE_DEVICE_TABLE(i2c, tvp7002_id); >>>> + >>>> +/* I2C driver data */ >>>> +static struct i2c_driver tvp7002_driver = { >>>> + .driver = { >>>> + .owner = THIS_MODULE, >>>> + .name = "tvp7002", >>>> + }, >>>> + .probe = tvp7002_probe, >>>> + .remove = tvp7002_remove, >>>> + .id_table = tvp7002_id, >>>> +}; >>>> + >>>> +/* >>>> + * tvp7002_init - Initialize driver via I2C interface >>>> + * >>>> + * Register the TVP7002 driver. >>>> + * Returns 0 on success or < 0 on failure. >>>> + */ >>>> +static int __init tvp7002_init(void) >>>> +{ >>>> + return i2c_add_driver(&tvp7002_driver); >>>> +} >>>> + >>>> +/* >>>> + * tvp7002_exit - Remove driver via I2C interface >>>> + * >>>> + * Unregister the TVP7002 driver. >>>> + * Returns 0 on success or < 0 on failure. >>>> + */ >>>> +static void __exit tvp7002_exit(void) >>>> +{ >>>> + i2c_del_driver(&tvp7002_driver); >>>> +} >>>> + >>>> +module_init(tvp7002_init); >>>> +module_exit(tvp7002_exit); >>>> -- >>>> 1.6.0.4 >>>> >>>> >> >> > > >-- >Santiago Nunez-Corrales, Eng. >RidgeRun Engineering, LLC > >Guayabos, Curridabat >San Jose, Costa Rica >+(506) 2271 1487 >+(506) 8313 0536 >http://www.ridgerun.com > > _______________________________________________ Davinci-linux-open-source mailing list [email protected] http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
