summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobby Cai <R63905@freescale.com>2013-07-04 17:31:24 +0800
committerRobby Cai <R63905@freescale.com>2013-07-10 20:25:49 +0800
commitbd45a30f3f305d8212771b572734606a42ca1108 (patch)
treebec4b4ebb0d65997762f9e49921393a4962fa36d
parentbfa270d00180f3faf8d304c104f3314743740209 (diff)
ENGR00261293-2 mx6sl: csi/v4l2: add hflip/vflip/rotation support
Use ePxP to do the horizontal/vertical flip and rotation support Signed-off-by: Robby Cai <R63905@freescale.com> (cherry picked from commit d0b9c741601b766213af1332329963f4267cd0c6)
-rw-r--r--drivers/media/video/mxc/capture/csi_v4l2_capture.c138
1 files changed, 129 insertions, 9 deletions
diff --git a/drivers/media/video/mxc/capture/csi_v4l2_capture.c b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
index fe6a89c2d48a..790ed05b0c13 100644
--- a/drivers/media/video/mxc/capture/csi_v4l2_capture.c
+++ b/drivers/media/video/mxc/capture/csi_v4l2_capture.c
@@ -65,6 +65,37 @@ static struct v4l2_int_device csi_v4l2_int_device = {
},
};
+static struct v4l2_queryctrl pxp_controls[] = {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rotation",
+ .minimum = 0,
+ .maximum = 270,
+ .step = 90,
+ .default_value = 0,
+ .flags = 0,
+ },
+};
+
/* Callback function triggered after PxP receives an EOF interrupt */
static void pxp_dma_done(void *arg)
{
@@ -194,7 +225,6 @@ static int pxp_process_update(cam_data *cam)
proc_data->drect.width = proc_data->srect.width;
proc_data->drect.height = proc_data->srect.height;
-
if (win_current.w.left != 0)
proc_data->drect.left = win_current.w.left;
if (win_current.w.top != 0)
@@ -204,16 +234,18 @@ static int pxp_process_update(cam_data *cam)
if (win_current.w.height != 0)
proc_data->drect.height = win_current.w.height;
- proc_data->hflip = 0;
- proc_data->vflip = 0;
- proc_data->rotate = 0;
- proc_data->bgcolor = 0;
+ pr_debug("srect l: %d, t: %d, w: %d, h: %d; "
+ "drect l: %d, t: %d, w: %d, h: %d\n",
+ proc_data->srect.left, proc_data->srect.top,
+ proc_data->srect.width, proc_data->srect.height,
+ proc_data->drect.left, proc_data->drect.top,
+ proc_data->drect.width, proc_data->drect.height);
pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
pxp_conf->out_param.width = proc_data->drect.width;
pxp_conf->out_param.height = proc_data->drect.height;
- if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+ if (cam->rotation % 180)
pxp_conf->out_param.stride = pxp_conf->out_param.height;
else
pxp_conf->out_param.stride = pxp_conf->out_param.width;
@@ -764,7 +796,7 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
* camera can change. */
pr_debug("csi_v4l2_s_fmt size changed\n");
}
- if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ if (cam->rotation % 180) {
height = &f->fmt.pix.width;
width = &f->fmt.pix.height;
} else {
@@ -850,6 +882,7 @@ static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
size = win_current.w.width * win_current.w.height * 2;
if (cam->v2f.fmt.pix.sizeimage < size)
cam->v2f.fmt.pix.sizeimage = size;
+
break;
default:
retval = -EINVAL;
@@ -923,6 +956,39 @@ exit:
return err;
}
+static int pxp_set_cstate(cam_data *cam, struct v4l2_control *vc)
+{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
+
+ if (vc->id == V4L2_CID_HFLIP) {
+ proc_data->hflip = vc->value;
+ } else if (vc->id == V4L2_CID_VFLIP) {
+ proc_data->vflip = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
+ if (vc->value % 90)
+ return -ERANGE;
+ proc_data->rotate = vc->value;
+ cam->rotation = vc->value;
+ }
+
+ return 0;
+}
+
+static int pxp_get_cstate(cam_data *cam, struct v4l2_control *vc)
+{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
+
+ if (vc->id == V4L2_CID_HFLIP)
+ vc->value = proc_data->hflip;
+ else if (vc->id == V4L2_CID_VFLIP)
+ vc->value = proc_data->vflip;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE)
+ vc->value = proc_data->rotate;
+
+ return 0;
+}
+
+
/*!
* Dequeue one V4L capture buffer
*
@@ -1451,15 +1517,63 @@ static long csi_v4l_do_ioctl(struct file *file,
}
case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id) {
+ if (vc->value < pxp_controls[i].minimum ||
+ vc->value > pxp_controls[i].maximum) {
+ retval = -ERANGE;
+ break;
+ }
+ retval = pxp_set_cstate(cam, vc);
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *vc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id) {
+ retval = pxp_get_cstate(cam, vc);
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (qc->id && qc->id == pxp_controls[i].id) {
+ memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(pxp_controls))
+ retval = -EINVAL;
+ break;
+ }
case VIDIOC_G_STD:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_ENUMSTD:
case VIDIOC_CROPCAP:
case VIDIOC_S_STD:
- case VIDIOC_G_CTRL:
case VIDIOC_TRY_FMT:
- case VIDIOC_QUERYCTRL:
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
@@ -1559,8 +1673,14 @@ static struct video_device csi_v4l_template = {
*/
static void init_camera_struct(cam_data *cam)
{
+ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data;
pr_debug("In MVC: %s\n", __func__);
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = 0;
+ proc_data->bgcolor = 0;
+
/* Default everything to 0 */
memset(cam, 0, sizeof(cam_data));