Santiago,
I am attaching a test application for I2C, which can be used to dump registers
for a device connected to I2C.
This is how you use it -
usage:
i2c CHIP -r ADDR ADDR_SIZE COUNT
Example (for TVP7002 address - 0x5c)
./i2c 0x5c -r 0 0 0x60
I am also attaching the dump from LSP 2.10, while running the loopback
application for 720p resolution. You can find the applications at
PSP_02_10_00_14/examples folder of the release.
You can dump the TVP7002 address space and compare it with the one from LSP
2.10.
Thanks
sneha
> -----Original Message-----
> From: Santiago Nunez-Corrales [mailto:[email protected]]
> Sent: Friday, September 04, 2009 4:45 PM
> To: Karicheri, Muralidharan
> Cc: Narnakaje, Snehaprabha; davinci-linux-open-
> [email protected]; [email protected];
> [email protected]; [email protected]
> Subject: Re: [PATCH 5/6 v4] Updated TVP7002 driver for DM365
>
> Murali,
>
>
> My current plan is:
>
>
> 1. Adapt my current code with the code in the LSP 2.10. In particular,
> use registers TVP7002_L_P_FRAME_STAT and TVP7002_CLK_P_L_STAT for
> detecting input configurations.
> 2. Review currently supported standards in the driver, check them and
> update any pertinent change. In particular, double-check register values
> with LSP code.
> 3. Add debugging functions for detection of standards.
> 4. Test module integrity (i.e. compilation).
> 5. Test module loading.
> 6. Use a component input to check detection of standards (480i to 1080p)
> and obtained data.
> 7. Fix and repeat from 4 until no errors are found.
> 8. Have a user space application to test video decoding.
>
>
> Regards,
>
>
>
> Karicheri, Muralidharan wrote:
> > 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; davinci-linux-open-
> [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
> >>
> >>
> >>
> >
> >
>
>
> --
> Santiago Nunez-Corrales, Eng.
> RidgeRun Engineering, LLC
>
> Guayabos, Curridabat
> San Jose, Costa Rica
> +(506) 2271 1487
> +(506) 8313 0536
> http://www.ridgerun.com
>
>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <unistd.h>
#include <sys/ioctl.h>
unsigned char bufAddr[5];
unsigned char* buf = NULL;
void help()
{
printf("usage:\n");
printf("i2c CHIP -r ADDR ADDR_SIZE COUNT\n");
printf("i2c CHIP -w ADDR ADDR_SIZE VALUE\n");
printf("i2c CHIP -sr\n");
printf("i2c CHIP -sw VALUE\n");
}
/**
* Super-safe conversion of a string into an unsigned.
* It exits the application on failure.
*/
unsigned long getUnsigned(const char* szParam)
{
char* szEndPtr = NULL;
unsigned long uResult = strtoul(szParam, &szEndPtr, 0);
if( (szParam[0] != '\0') &&
(*szEndPtr == '\0'))
{
if(uResult == ULONG_MAX)
{
printf("Too large integer: %s\n", szParam);
exit(1);
}
return uResult;
}
printf("Invalid value : %s\n", szParam);
exit(1);
}
int main_short(int argc, char** argv)
{
int iFd;
int iRes;
char* szCmd = NULL;
if(argc == 3)
{
szCmd = argv[2];
if(strcmp(szCmd, "-sr") != 0)
{
help();
return 1;
}
}
else if(argc == 4)
{
szCmd = argv[2];
if(strcmp(szCmd, "-sw") != 0)
{
help();
return 1;
}
}
else
{
help();
return 1;
}
/* We open the I2C bus. */
iFd = open("/dev/i2c-0", O_RDWR);
if(iFd < 0)
{
printf("Cannot open I2C device\n");
return 1;
}
char* szChip = argv[1];
char* szData = NULL;
unsigned char ucChip;
unsigned char ucData;
ucChip = (unsigned char)(getUnsigned(szChip));
if(argc == 4)
{
szData = argv[3];
ucData = (unsigned char)(getUnsigned(szData));
}
struct i2c_msg msgs[1];
struct i2c_rdwr_ioctl_data data;
msgs[0].addr = ucChip;
msgs[0].flags = (argc == 3) ? I2C_M_RD : 0;
msgs[0].len = 1;
msgs[0].buf = &ucData;
data.msgs = msgs;
data.nmsgs = 1;
iRes = ioctl(iFd, I2C_RDWR, &data);
if(iRes >= 0)
{
if(argc == 3)
printf("0x%x\n", ucData);
}
else
printf("IOCTL failed iRes=%i\n", iRes);
close(iFd);
return 0;
}
int main(int argc, char** argv)
{
int iFd;
int iRes;
int i;
/* We open the I2C bus. */
iFd = open("/dev/i2c-0", O_RDWR);
if(iFd < 0)
{
printf("Cannot open I2C device\n");
return 1;
}
unsigned char ucChip;
int bRead = 0;
unsigned long uAddr;
unsigned long uAddrSize;
unsigned long uValueOrCount;
if(argc == 3 || argc == 4)
return main_short(argc, argv);
else
if(argc != 6)
{
help();
return 1;
}
char* szChip = argv[1];
char* szReadWrite = argv[2];
char* szAddr = argv[3];
char* szAddrSize = argv[4];
char* szValueOrCount = argv[5];
ucChip = (unsigned char)(getUnsigned(szChip));
if(strncmp(szReadWrite, "-r", 2) == 0)
bRead = 1;
else if(strncmp(szReadWrite, "-w", 2) == 0)
bRead = 0;
else
{
help();
return 1;
}
uAddr = getUnsigned(szAddr);
uAddrSize = getUnsigned(szAddrSize);
if(uAddrSize > 4)
{
help();
return 1;
}
uValueOrCount = getUnsigned(szValueOrCount);
if(!bRead && uValueOrCount > 255)
{
help();
return 1;
}
if(bRead)
{
buf = (unsigned char*)malloc(uValueOrCount);
if(buf == NULL)
{
printf("Cannot allocate %lu bytes\n", uValueOrCount);
return 1;
}
}
struct i2c_msg msgs[2];
struct i2c_rdwr_ioctl_data data;
if(bRead)
{
for(i=0; i < uAddrSize; i++)
bufAddr[i] = ((unsigned char*)&uAddr)[uAddrSize-1-i];
msgs[0].addr = ucChip;
msgs[0].flags = 0;
msgs[0].len = uAddrSize;
msgs[0].buf = bufAddr;
msgs[1].addr = ucChip;
msgs[1].flags = I2C_M_RD /* | I2C_M_REV_DIR_ADDR */;
msgs[1].len = uValueOrCount;
msgs[1].buf = buf;
data.msgs = msgs;
data.nmsgs = 2;
}
else
{
for(i=0; i < uAddrSize; i++)
bufAddr[i] = ((unsigned char*)&uAddr)[uAddrSize-1-i];
bufAddr[uAddrSize] = uValueOrCount;
msgs[0].addr = ucChip;
msgs[0].flags = 0;
msgs[0].len = uAddrSize + 1;
msgs[0].buf = bufAddr;
data.msgs = msgs;
data.nmsgs = 1;
}
iRes = ioctl(iFd, I2C_RDWR, &data);
if(iRes >= 0)
{
if(bRead)
{
for(i=0; i<uValueOrCount; i++)
printf("0x%x\n", buf[i]);
}
else
printf("Success !\n");
}
else
printf("IOCTL failed iRes=%i\n", iRes);
close(iFd);
return 0;
}
# ./i2c-lsp210 0x5c -r 0 0 0x60
0x2
0x67
0x20
0xa0
0x80
0x32
0x20
0x60
0x0
0x0
0x0
0x80
0x80
0x80
0x20
0x2e
0x5d
0x47
0x0
0x0
0x6f
0x47
0x1
0x0
0x1
0x0
0x67
0x77
0x7
0x0
0x10
0x10
0x10
0x8
0x0
0x4a
0x25
0x39
0x80
0x8
0x53
0x8
0x7
0x0
0x50
0x0
0x80
0x8c
0x4
0x5a
0x18
0x60
0x3
0x10
0x0
0xee
0x22
0x8b
0x0
0x3
0x5
0x3
0x4
0x1
0x47
0x1
0x4b
0x6
0x5
0x0
0x2d
0x0
0x0
0x0
0xe3
0x16
0x4f
0x2
0xce
0x6
0xab
0xf3
0x0
0x10
0x55
0xfc
0x78
0xf1
0x88
0xfe
0x0
0x10
0x0
0x0
0x0
0x0
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source