From: Vaibhav Hiremath <hvaibhav@xxxxxx> Support for BT656 through TVP5146 decoder, works on top of ISP-Camera patches posted by Sergio on 12th Dec 2008. The TVP514x driver patch has been accepted under V4L, will be part of O-L in the next merge window. As of now you can access the patches from - http://markmail.org/search/?q=TVP514x#query:TVP514x%20from%3A%22Hiremath%2C%20Vaibhav%22%20extension%3Apatch+page:1+mid:b5pcj3sriwknm2cv+state:results Patch has been tested on OMAP3EVM for BT656 support, these changes will not affect the existing ensor support (verified on OMAP3SDP board). ToDO List: - Refresh the patch with the Sergio's updated ISP-Camera patches (Fix for review comments) - Add support for OMAP3 Mass Market Daughter Card - Add support for scaling and cropping Signed-off-by: Brijesh Jadav <brijesh.j@xxxxxx> Signed-off-by: Hardik Shah <hardik.shah@xxxxxx> Signed-off-by: Manjunath Hadli <mrh@xxxxxx> Signed-off-by: R Sivaraj <sivaraj@xxxxxx> Signed-off-by: Vaibhav Hiremath <hvaibhav@xxxxxx> --- drivers/media/video/isp/isp.c | 121 ++++++++++++++++++++--- drivers/media/video/isp/isp.h | 7 +- drivers/media/video/isp/ispccdc.c | 132 ++++++++++++++++++++++--- drivers/media/video/isp/ispccdc.h | 9 ++ drivers/media/video/omap34xxcam.c | 197 +++++++++++++++++++++++++++++++++---- drivers/media/video/omap34xxcam.h | 5 + 6 files changed, 424 insertions(+), 47 deletions(-) diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c index f117f36..a64b8bf 100644 --- a/drivers/media/video/isp/isp.c +++ b/drivers/media/video/isp/isp.c @@ -191,6 +191,7 @@ struct isp_sgdma ispsg; * @resizer_input_height: ISP Resizer module input image height. * @resizer_output_width: ISP Resizer module output image width. * @resizer_output_height: ISP Resizer module output image height. + * @current_field: Current field for interlaced capture. */ struct ispmodule { unsigned int isp_pipeline; @@ -209,6 +210,7 @@ struct ispmodule { unsigned int resizer_input_height; unsigned int resizer_output_width; unsigned int resizer_output_height; + int current_field; }; static struct ispmodule ispmodule_obj = { @@ -224,11 +226,14 @@ static struct ispmodule ispmodule_obj = { .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0, }, + .current_field = 0, }; /* Structure for saving/restoring ISP module registers */ static struct isp_reg isp_reg_list[] = { {ISP_SYSCONFIG, 0}, + {ISP_IRQ0ENABLE, 0}, + {ISP_IRQ1ENABLE, 0}, {ISP_TCTRL_GRESET_LENGTH, 0}, {ISP_TCTRL_PSTRB_REPLAY, 0}, {ISP_CTRL, 0}, @@ -550,6 +555,11 @@ EXPORT_SYMBOL(isp_unset_callback); **/ int isp_request_interface(enum isp_interface_type if_t) { + enum isp_interface_type temp_if_t = if_t; + + if (if_t == ISP_PARLL_YUV_BT) + if_t = ISP_PARLL; + if (isp_obj.if_status & if_t) { DPRINTK_ISPCTRL("ISP_ERR : Requested Interface already \ allocated\n"); @@ -569,7 +579,7 @@ int isp_request_interface(enum isp_interface_type if_t) ((isp_obj.if_status == ISP_CSIB) && (if_t == ISP_CSIA)) || (isp_obj.if_status == 0)) { - isp_obj.if_status |= if_t; + isp_obj.if_status |= (if_t | temp_if_t); return 0; } else { DPRINTK_ISPCTRL("ISP_ERR : Invalid Combination Serial- \ @@ -590,6 +600,9 @@ EXPORT_SYMBOL(isp_request_interface); **/ int isp_free_interface(enum isp_interface_type if_t) { + if ((if_t == ISP_PARLL) || (if_t == ISP_PARLL_YUV_BT)) + if_t |= (ISP_PARLL | ISP_PARLL_YUV_BT); + isp_obj.if_status &= ~if_t; return 0; } @@ -891,6 +904,7 @@ int isp_configure_interface(struct isp_interface_config *config) ispctrl_val &= (ISPCTRL_PAR_SER_CLK_SEL_MASK); switch (config->ccdc_par_ser) { case ISP_PARLL: + case ISP_PARLL_YUV_BT: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; ispctrl_val |= (config->u.par.par_clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT); @@ -1348,9 +1362,14 @@ u32 isp_calc_pipeline(struct v4l2_pix_format *pix_input, ispccdc_request(); if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10) ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP_MEM); - else - ispccdc_config_datapath(CCDC_YUV_SYNC, - CCDC_OTHERS_MEM); + else { + if (isp_obj.if_status & ISP_PARLL_YUV_BT) + ispccdc_config_datapath(CCDC_YUV_BT, + CCDC_OTHERS_MEM); + else + ispccdc_config_datapath(CCDC_YUV_SYNC, + CCDC_OTHERS_MEM); + } } return 0; } @@ -1384,6 +1403,31 @@ void isp_config_pipeline(struct v4l2_pix_format *pix_input, ispmodule_obj.resizer_output_width, ispmodule_obj.resizer_output_height); } + if (pix_input->pixelformat == V4L2_PIX_FMT_UYVY) + ispccdc_config_y8pos(Y8POS_ODD); + else if (pix_input->pixelformat == V4L2_PIX_FMT_YUYV) + ispccdc_config_y8pos(Y8POS_EVEN); + + if (((pix_input->pixelformat == V4L2_PIX_FMT_UYVY) && + (pix_output->pixelformat == V4L2_PIX_FMT_UYVY)) || + ((pix_input->pixelformat == V4L2_PIX_FMT_YUYV) && + (pix_output->pixelformat == V4L2_PIX_FMT_YUYV))) + /* input and output formats are in same order */ + ispccdc_config_byteswap(0); + else if (((pix_input->pixelformat == V4L2_PIX_FMT_YUYV) && + (pix_output->pixelformat == V4L2_PIX_FMT_UYVY)) || + ((pix_input->pixelformat == V4L2_PIX_FMT_UYVY) && + (pix_output->pixelformat == V4L2_PIX_FMT_YUYV))) + /* input and output formats are in reverse order */ + ispccdc_config_byteswap(1); + + /* + * Configure Pitch - This enables application to use a different pitch + * other than active pixels per line. + */ + if (isp_obj.if_status & ISP_PARLL_YUV_BT) + ispccdc_config_outlineoffset(ispmodule_obj.pix.bytesperline, + 0, 0); if (pix_output->pixelformat == V4L2_PIX_FMT_UYVY) { isppreview_config_ycpos(YCPOS_YCrYCb); @@ -1410,9 +1454,23 @@ void isp_vbq_done(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2) int notify = 0; int rval = 0; unsigned long flags; + unsigned long fld_stat = (omap_readl(ISPCCDC_SYN_MODE) >> 15) & 0x1; switch (status) { case CCDC_VD0: + if (ispmodule_obj.pix.field == V4L2_FIELD_INTERLACED) { + spin_lock(&isp_obj.isp_temp_buf_lock); + /* Skip even fields */ + if (ispmodule_obj.current_field != fld_stat) { + if (fld_stat == 0) + ispmodule_obj.current_field = fld_stat; + + spin_unlock(&isp_obj.isp_temp_buf_lock); + return; + } + spin_unlock(&isp_obj.isp_temp_buf_lock); + } + ispccdc_config_shadow_registers(); if ((ispmodule_obj.isp_pipeline & OMAP_ISP_RESIZER) || (ispmodule_obj.isp_pipeline & OMAP_ISP_PREVIEW)) @@ -1430,6 +1488,20 @@ void isp_vbq_done(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2) } break; case CCDC_VD1: + if (ispmodule_obj.pix.field == V4L2_FIELD_INTERLACED) { + spin_lock(&isp_obj.isp_temp_buf_lock); + if (ispmodule_obj.current_field != fld_stat) { + if (fld_stat == 0) + ispmodule_obj.current_field = fld_stat; + + spin_unlock(&isp_obj.isp_temp_buf_lock); + return; + } + spin_unlock(&isp_obj.isp_temp_buf_lock); + if (fld_stat == 0) /* Skip even fields */ + return; + } + if ((ispmodule_obj.isp_pipeline & OMAP_ISP_RESIZER) || (ispmodule_obj.isp_pipeline & OMAP_ISP_PREVIEW)) return; @@ -1476,13 +1548,26 @@ void isp_vbq_done(unsigned long status, isp_vbq_callback_ptr arg1, void *arg2) } break; case HS_VS: - spin_lock(&isp_obj.isp_temp_buf_lock); - if (ispmodule_obj.isp_temp_state == ISP_BUF_TRAN) { - isp_CCDC_VD01_enable(); - ispmodule_obj.isp_temp_state = ISP_BUF_INIT; + if (ispmodule_obj.pix.field == V4L2_FIELD_INTERLACED) { + ispmodule_obj.current_field ^= 1; + spin_lock(&isp_obj.isp_temp_buf_lock); + if ((ispmodule_obj.isp_temp_state == ISP_BUF_TRAN) && + (fld_stat == 1)) { + isp_CCDC_VD01_enable(); + ispmodule_obj.current_field = fld_stat; + ispmodule_obj.isp_temp_state = ISP_BUF_INIT; + } + spin_unlock(&isp_obj.isp_temp_buf_lock); + return; + } else { + spin_lock(&isp_obj.isp_temp_buf_lock); + if (ispmodule_obj.isp_temp_state == ISP_BUF_TRAN) { + isp_CCDC_VD01_enable(); + ispmodule_obj.isp_temp_state = ISP_BUF_INIT; + } + spin_unlock(&isp_obj.isp_temp_buf_lock); + return; } - spin_unlock(&isp_obj.isp_temp_buf_lock); - return; default: return; } @@ -2204,15 +2289,25 @@ int isp_try_fmt(struct v4l2_pix_format *pix_input, if (ifmt == NUM_ISP_CAPTURE_FORMATS) ifmt = 1; pix_output->pixelformat = isp_formats[ifmt].pixelformat; - pix_output->field = V4L2_FIELD_NONE; - pix_output->bytesperline = pix_output->width * ISP_BYTES_PER_PIXEL; + + if (isp_obj.if_status & ISP_PARLL_YUV_BT) + pix_output->field = pix_input->field; + else { + pix_output->field = V4L2_FIELD_NONE; + pix_output->bytesperline = + pix_output->width * ISP_BYTES_PER_PIXEL; + } + pix_output->sizeimage = PAGE_ALIGN(pix_output->bytesperline * pix_output->height); pix_output->priv = 0; switch (pix_output->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: - pix_output->colorspace = V4L2_COLORSPACE_JPEG; + if (isp_obj.if_status & ISP_PARLL_YUV_BT) + pix_output->colorspace = pix_input->colorspace; + else + pix_output->colorspace = V4L2_COLORSPACE_JPEG; break; default: pix_output->colorspace = V4L2_COLORSPACE_SRGB; diff --git a/drivers/media/video/isp/isp.h b/drivers/media/video/isp/isp.h index aac7056..27f192a 100644 --- a/drivers/media/video/isp/isp.h +++ b/drivers/media/video/isp/isp.h @@ -73,7 +73,8 @@ typedef void (*isp_callback_t) (unsigned long status, enum isp_interface_type { ISP_PARLL = 1, ISP_CSIA = 2, - ISP_CSIB = 4 + ISP_CSIB = 4, + ISP_PARLL_YUV_BT = 8 }; enum isp_irqevents { @@ -302,6 +303,10 @@ int isp_try_size(struct v4l2_pix_format *pix_input, int isp_try_fmt(struct v4l2_pix_format *pix_input, struct v4l2_pix_format *pix_output); +int isp_configure_std(struct v4l2_pix_format *fmt); + +int isp_check_format(struct v4l2_pix_format *pixfmt); + int isp_handle_private(int cmd, void *arg); void isp_save_context(struct isp_reg *); diff --git a/drivers/media/video/isp/ispccdc.c b/drivers/media/video/isp/ispccdc.c index 9167f54..259606d 100644 --- a/drivers/media/video/isp/ispccdc.c +++ b/drivers/media/video/isp/ispccdc.c @@ -567,8 +567,10 @@ int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output) syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; syn_mode |= ISPCCDC_SYN_MODE_WEN; syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN; - omap_writel((omap_readl(ISPCCDC_CFG)) & ~ISPCCDC_CFG_WENLOG, - ISPCCDC_CFG); + omap_writel((omap_readl(ISPCCDC_CFG)) & + ~ISPCCDC_CFG_WENLOG, + ISPCCDC_CFG); + vpcfg.bitshift_sel = BIT11_2; vpcfg.freq_sel = PIXCLKBY2; ispccdc_config_vp(vpcfg); @@ -627,12 +629,28 @@ int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output) syncif.hdpol = 0; syncif.ipmod = YUV16; syncif.vdpol = 0; + syncif.bt_r656_en = 0; ispccdc_config_imgattr(0); ispccdc_config_sync_if(syncif); blkcfg.dcsubval = 0; ispccdc_config_black_clamp(blkcfg); break; case CCDC_YUV_BT: + syncif.ccdc_mastermode = 0; + syncif.datapol = 0; + syncif.datsz = DAT8; + syncif.fldmode = 1; + syncif.fldout = 0; + syncif.fldpol = 0; + syncif.fldstat = 0; + syncif.hdpol = 0; + syncif.ipmod = YUV8; + syncif.vdpol = 1; + syncif.bt_r656_en = 1; + ispccdc_config_imgattr(0); + ispccdc_config_sync_if(syncif); + blkcfg.dcsubval = 0; + ispccdc_config_black_clamp(blkcfg); break; case CCDC_OTHERS: break; @@ -677,6 +695,8 @@ void ispccdc_config_sync_if(struct ispccdc_syncif syncif) break; case YUV8: syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8; + if (syncif.bt_r656_en) + syn_mode |= ISPCCDC_SYN_MODE_PACK8; break; }; @@ -741,6 +761,11 @@ void ispccdc_config_sync_if(struct ispccdc_syncif syncif) omap_writel((omap_readl(ISPCCDC_REC656IF)) & ~ISPCCDC_REC656IF_R656ON, ISPCCDC_REC656IF); + } else { + omap_writel((omap_readl(ISPCCDC_REC656IF)) | + (ISPCCDC_REC656IF_R656ON | + ISPCCDC_REC656IF_ECCFVH), + ISPCCDC_REC656IF); } } EXPORT_SYMBOL(ispccdc_config_sync_if); @@ -1178,35 +1203,78 @@ int ispccdc_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h) } else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_MEM) { omap_writel(0, ISPCCDC_VP_OUT); if (cpu_is_omap3410()) { - omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT | + if (ispccdc_obj.ccdc_inpfmt != CCDC_YUV_BT) + omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT | ((ispccdc_obj.ccdcout_w - 1) << - ISPCCDC_HORZ_INFO_NPH_SHIFT), + ISPCCDC_HORZ_INFO_NPH_SHIFT), ISPCCDC_HORZ_INFO); + else + omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT | + (((ispccdc_obj.ccdcout_w << 1) - 1) << + ISPCCDC_HORZ_INFO_NPH_SHIFT), + ISPCCDC_HORZ_INFO); } else { - if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) { - omap_writel(1 << ISPCCDC_HORZ_INFO_SPH_SHIFT + if (ispccdc_obj.ccdc_inpfmt != CCDC_YUV_BT) { + if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) { + omap_writel(1 << ISPCCDC_HORZ_INFO_SPH_SHIFT | ((ispccdc_obj.ccdcout_w - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), ISPCCDC_HORZ_INFO); - } else { - omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT + else + omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT | ((ispccdc_obj.ccdcout_w - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), ISPCCDC_HORZ_INFO); - } + } else + omap_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT | + (((ispccdc_obj.ccdcout_w << 1) - 1) << + ISPCCDC_HORZ_INFO_NPH_SHIFT), + ISPCCDC_HORZ_INFO); + } + + if (ispccdc_obj.ccdc_inpfmt != CCDC_YUV_BT) { + omap_writel(0 << ISPCCDC_VERT_START_SLV0_SHIFT, + ISPCCDC_VERT_START); + omap_writel((ispccdc_obj.ccdcout_h - 1) << + ISPCCDC_VERT_LINES_NLV_SHIFT, + ISPCCDC_VERT_LINES); + } else { + omap_writel(2 << ISPCCDC_VERT_START_SLV0_SHIFT | + 2 << ISPCCDC_VERT_START_SLV1_SHIFT, + ISPCCDC_VERT_START); + omap_writel(((ispccdc_obj.ccdcout_h >> 1) - 1) << + ISPCCDC_VERT_LINES_NLV_SHIFT, + ISPCCDC_VERT_LINES); } - omap_writel(0 << ISPCCDC_VERT_START_SLV0_SHIFT, - ISPCCDC_VERT_START); - omap_writel((ispccdc_obj.ccdcout_h - 1) << - ISPCCDC_VERT_LINES_NLV_SHIFT, - ISPCCDC_VERT_LINES); ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, 0, 0); - omap_writel((((ispccdc_obj.ccdcout_h - 2) & + + if (ispccdc_obj.ccdc_inpfmt != CCDC_YUV_BT) { + omap_writel((((ispccdc_obj.ccdcout_h - 2) & ISPCCDC_VDINT_0_MASK) << ISPCCDC_VDINT_0_SHIFT) | ((50 & ISPCCDC_VDINT_1_MASK) << ISPCCDC_VDINT_1_SHIFT), ISPCCDC_VDINT); + } else { + ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, + EVENEVEN, + 1); + ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, + ODDEVEN, + 1); + ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, + EVENODD, + 1); + ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, + ODDODD, + 1); + + omap_writel(((((ispccdc_obj.ccdcout_h >> 1) - 1) & + ISPCCDC_VDINT_0_MASK) << + ISPCCDC_VDINT_0_SHIFT) | + ((50 & ISPCCDC_VDINT_1_MASK) << + ISPCCDC_VDINT_1_SHIFT), ISPCCDC_VDINT); + } } else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP_MEM) { omap_writel((1 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | (ispccdc_obj.ccdcin_w << @@ -1356,6 +1424,40 @@ void ispccdc_enable(u8 enable) EXPORT_SYMBOL(ispccdc_enable); /** + * ispccdc_config_y8pos - Configures the location of Y color component + * @mode: Y8POS_EVEN Y pixel in even position, otherwise Y pixel in odd + * + * Configures the location of Y color componenent for YCbCr 8-bit data + */ +void ispccdc_config_y8pos(enum y8pos_mode mode) +{ + if (mode == Y8POS_EVEN) + omap_writel(omap_readl(ISPCCDC_CFG) & ~(ISPCCDC_CFG_Y8POS), + ISPCCDC_CFG); + else + omap_writel(omap_readl(ISPCCDC_CFG) | (ISPCCDC_CFG_Y8POS), + ISPCCDC_CFG); +} +EXPORT_SYMBOL(ispccdc_config_y8pos); + +/** + * ispccdc_config_byteswap - Configures byte swap data stored in memory + * @swap: 1 - swap bytes, 0 - normal + * + * Controls the order in which the Y and C pixels are stored in memory + */ +void ispccdc_config_byteswap(int swap) +{ + if (swap) + omap_writel(omap_readl(ISPCCDC_CFG) | (ISPCCDC_CFG_BSWD), + ISPCCDC_CFG); + else + omap_writel(omap_readl(ISPCCDC_CFG) & ~(ISPCCDC_CFG_BSWD), + ISPCCDC_CFG); +} +EXPORT_SYMBOL(ispccdc_config_byteswap); + +/** * ispccdc_busy - Gets busy state of the CCDC. **/ int ispccdc_busy(void) diff --git a/drivers/media/video/isp/ispccdc.h b/drivers/media/video/isp/ispccdc.h index 9ee67ce..a5e7b14 100644 --- a/drivers/media/video/isp/ispccdc.h +++ b/drivers/media/video/isp/ispccdc.h @@ -66,6 +66,11 @@ enum datasize { DAT12 }; +/* Enumeration constants for location of Y component in 8-bit YUV data */ +enum y8pos_mode { + Y8POS_EVEN = 0, + Y8POS_ODD = 1 +}; /** * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC @@ -197,6 +202,10 @@ int ispccdc_set_outaddr(u32 addr); void ispccdc_enable(u8 enable); +void ispccdc_config_y8pos(enum y8pos_mode mode); + +void ispccdc_config_byteswap(int swap); + int ispccdc_busy(void); void ispccdc_save_context(void); diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c index 31b6b60..e90e7e8 100644 --- a/drivers/media/video/omap34xxcam.c +++ b/drivers/media/video/omap34xxcam.c @@ -56,6 +56,8 @@ #include "isp/isppreview.h" #include "isp/ispresizer.h" +#include <media/tvp514x.h> + #define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0) /* global variables */ @@ -262,7 +264,8 @@ static int omap34xxcam_vbq_prepare(struct videobuf_queue *vbq, */ if (vb->baddr) { /* This is a userspace buffer. */ - if (fh->pix.sizeimage > vb->bsize) + if ((fh->pix.sizeimage > vb->bsize) || + vb->baddr != (vb->baddr & ~0x1F)) /* The buffer isn't big enough. */ return -EINVAL; } else { @@ -379,7 +382,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct omap34xxcam_videodev *vdev = ofh->vdev; int rval; - if (vdev->vdev_sensor_config.sensor_isp) + if (vdev->vdev_sensor_mode) + rval = isp_enum_fmt_cap(f); + else if (vdev->vdev_sensor_config.sensor_isp) rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, f); else rval = isp_enum_fmt_cap(f); @@ -403,7 +408,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct omap34xxcam_videodev *vdev = ofh->vdev; mutex_lock(&vdev->mutex); - f->fmt.pix = ofh->pix; + if (vdev->vdev_sensor_mode) + isp_g_fmt_cap(&f->fmt.pix); + else + f->fmt.pix = ofh->pix; mutex_unlock(&vdev->mutex); return 0; @@ -607,20 +615,44 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_pix_format pix_tmp; struct v4l2_fract timeperframe; int rval; + struct v4l2_format input_fmt = *f; mutex_lock(&vdev->mutex); if (vdev->streaming) { rval = -EBUSY; goto out; } + if (vdev->vdev_sensor_mode) { + struct v4l2_pix_format *pix = &f->fmt.pix; + rval = isp_try_fmt_cap(pix, pix); + if (rval) + goto out; - vdev->want_pix = f->fmt.pix; + /* Always negotiate with the sensor first */ + rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &input_fmt); + if (rval) + goto out; - timeperframe = vdev->want_timeperframe; + pix->width = input_fmt.fmt.pix.width; + pix->height = input_fmt.fmt.pix.height; + pix->pixelformat = input_fmt.fmt.pix.pixelformat; + pix->field = input_fmt.fmt.pix.field; + pix->bytesperline = input_fmt.fmt.pix.bytesperline; + pix->colorspace = input_fmt.fmt.pix.colorspace; + pix->sizeimage = input_fmt.fmt.pix.sizeimage; - rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe); - pix_tmp = f->fmt.pix; + /* Negotiate with OMAP3 ISP */ + rval = isp_s_fmt_cap(pix, pix); + if (!rval) + pix_tmp = f->fmt.pix; + } else { + vdev->want_pix = f->fmt.pix; + timeperframe = vdev->want_timeperframe; + + rval = s_pix_parm(vdev, &pix_tmp, &f->fmt.pix, &timeperframe); + pix_tmp = f->fmt.pix; + } out: mutex_unlock(&vdev->mutex); @@ -859,15 +891,28 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *inp) { - if (inp->index > 0) - return -EINVAL; - - strlcpy(inp->name, "camera", sizeof(inp->name)); - inp->type = V4L2_INPUT_TYPE_CAMERA; - + struct omap34xxcam_videodev *vdev = ((struct omap34xxcam_fh *)fh)->vdev; + + if (vdev->vdev_sensor_mode) { + if (vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR].cur_input + == INPUT_CVBS_VI2B) { + strlcpy(inp->name, "COMPOSITE", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + } else if (vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR] + .cur_input == INPUT_SVIDEO_VI2C_VI1C) { + strlcpy(inp->name, "S-VIDEO", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + } + } else { + if (inp->index > 0) + return -EINVAL; + strlcpy(inp->name, "camera", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + } return 0; } + /** * vidioc_g_input - V4L2 get input IOCTL handler * @file: ptr. to system file structure @@ -878,9 +923,35 @@ static int vidioc_enum_input(struct file *file, void *fh, */ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) { - *i = 0; + struct omap34xxcam_videodev *vdev = ((struct omap34xxcam_fh *)fh)->vdev; + int rval = 0; + + mutex_lock(&vdev->mutex); + if (vdev->vdev_sensor_mode) { + if (vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR].cur_input + == 0) { + struct v4l2_routing route; + route.input = INPUT_CVBS_VI2B; + route.output = 0; + rval = vidioc_int_s_video_routing(vdev->vdev_sensor, + &route); + if (!rval) + vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR] + .cur_input = route.input; + } + if (vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR].cur_input + == INPUT_CVBS_VI2B) + *i = 0; + else if (vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR].cur_input + == INPUT_SVIDEO_VI2C_VI1C) + *i = 1; + } else + *i = 0; + + mutex_unlock(&vdev->mutex); + + return rval; - return 0; } /** @@ -893,10 +964,30 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) */ static int vidioc_s_input(struct file *file, void *fh, unsigned int i) { - if (i > 0) - return -EINVAL; + struct omap34xxcam_fh *ofh = fh; + struct omap34xxcam_videodev *vdev = ofh->vdev; + int rval = 0; + struct v4l2_routing route; - return 0; + mutex_lock(&vdev->mutex); + if (vdev->vdev_sensor_mode) { + if (i == 0) + route.input = INPUT_CVBS_VI2B; + else + route.input = INPUT_SVIDEO_VI2C_VI1C; + + route.output = 0; + rval = vidioc_int_s_video_routing(vdev->vdev_sensor, &route); + if (!rval) + vdev->slave_config[OMAP34XXCAM_SLAVE_SENSOR].cur_input + = route.input; + } else { + if (i > 0) + rval = -EINVAL; + } + mutex_unlock(&vdev->mutex); + + return rval; } /** @@ -1381,6 +1472,61 @@ out: return rval; } + +/** + * vidioc_querystd - V4L2 query current standard IOCTL handler + * @file: ptr. to system file structure + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data) + * @std: standard V4L2 v4l2_std_id enum + * + * If using a "smart" sensor, just forwards request to the sensor driver, + * otherwise returns error + */ +static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *std) +{ + struct omap34xxcam_fh *ofh = fh; + struct omap34xxcam_videodev *vdev = ofh->vdev; + int rval = 0; + + mutex_lock(&vdev->mutex); + if (vdev->vdev_sensor_mode) { + rval = vidioc_int_querystd(vdev->vdev_sensor, std); + if (rval == 0) + vdev->vfd->current_norm = *std; + } else + rval = -EINVAL; + mutex_unlock(&vdev->mutex); + + return rval; +} + +/** + * vidioc_s_std - V4L2 set standard IOCTL handler + * @file: ptr. to system file structure + * @fh: ptr to hold address of omap34xxcam_fh struct (per-filehandle data) + * @std: standard V4L2 v4l2_std_id enum + * + * If using a "smart" sensor, just forwards request to the sensor driver, + * otherwise returns error + */ +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *std) +{ + struct omap34xxcam_fh *ofh = fh; + struct omap34xxcam_videodev *vdev = ofh->vdev; + int rval = 0; + + mutex_lock(&vdev->mutex); + if (vdev->vdev_sensor_mode) { + rval = vidioc_int_s_std(vdev->vdev_sensor, std); + if (rval == 0) + vdev->vfd->current_norm = *std; + } else + rval = -EINVAL; + mutex_unlock(&vdev->mutex); + + return rval; +} + /* * * File operations. @@ -1683,6 +1829,8 @@ static const struct v4l2_ioctl_ops omap34xxcam_ioctl_ops = { .vidioc_g_crop = vidioc_g_crop, .vidioc_s_crop = vidioc_s_crop, .vidioc_default = vidioc_default, + .vidioc_s_std = vidioc_s_std, + .vidioc_querystd = vidioc_querystd, }; /** @@ -1704,6 +1852,7 @@ static int omap34xxcam_device_register(struct v4l2_int_device *s) struct omap34xxcam_hw_config hwc; struct video_device *vfd; int rval; + struct v4l2_ifparm ifparm; /* We need to check rval just once. The place is here. */ if (vidioc_int_g_priv(s, &hwc)) @@ -1783,6 +1932,18 @@ static int omap34xxcam_device_register(struct v4l2_int_device *s) } else { vfd = vdev->vfd; } + /*Determine whether the slave connected is BT656 decoder or a sensor*/ + if (!vidioc_int_g_ifparm(s, &ifparm)) { + if (ifparm.if_type == V4L2_IF_TYPE_BT656) { + vfd->current_norm = V4L2_STD_NTSC; + vfd->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; + if ((ifparm.u.bt656.mode == + V4L2_IF_TYPE_BT656_MODE_BT_8BIT) || + (ifparm.u.bt656.mode == + V4L2_IF_TYPE_BT656_MODE_BT_10BIT)) + vdev->slave_mode[hwc.dev_type] = 1; + } + } omap34xxcam_vfd_name_update(vdev); diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h index 36f7fd5..39e581c 100644 --- a/drivers/media/video/omap34xxcam.h +++ b/drivers/media/video/omap34xxcam.h @@ -92,6 +92,7 @@ struct omap34xxcam_hw_config { struct omap34xxcam_lens_config lens; struct omap34xxcam_flash_config flash; } u; + int cur_input; }; /** @@ -155,6 +156,10 @@ struct omap34xxcam_videodev { #define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens #define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1]; +#define vdev_sensor_mode slave_mode[OMAP34XXCAM_SLAVE_SENSOR] +#define vdev_lens_mode slave_mode[OMAP34XXCAM_SLAVE_LENS] +#define vdev_flash_mode slave_mode[OMAP34XXCAM_SLAVE_FLASH] + int slave_mode[OMAP34XXCAM_SLAVE_FLASH + 1]; /*** capture data ***/ struct v4l2_fract want_timeperframe; -- 1.5.6 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html