aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-fimc
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2011-08-24 18:25:10 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-09-06 16:39:33 -0400
commit131b6c619758ed8fd16d26b06a423801a497b867 (patch)
tree88c5069c9e9782a073c2dd72536db42f7dc27694 /drivers/media/video/s5p-fimc
parente578588eb01d9493513ca1527f464715cfd3f47f (diff)
[media] s5p-fimc: Convert to the new control framework
Convert the v4l controls code to use the new control framework. fimc_ctrls_activate/deactivate functions are introduced for the transparent DMA transfer mode (JPEG), where the rotation and flipping controls are not supported. The capture video node does not inherit sensors' controls when the subdevs are configured by the user space (user_subdev_api == true). However by default after the driver's initialization the 'user-subdev_api' flag is false and any sensor controls will also be available at the video node. When the pipeline links are disconnected through the media device the FIMC and any sensor inherited controls are destroyed and then again created when the pipeline connection completes. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-fimc')
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c61
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c291
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h34
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c11
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c32
5 files changed, 188 insertions, 241 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 562b23c7d486..0c237a776f8d 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -27,6 +27,7 @@
27#include <media/videobuf2-core.h> 27#include <media/videobuf2-core.h>
28#include <media/videobuf2-dma-contig.h> 28#include <media/videobuf2-dma-contig.h>
29 29
30#include "fimc-mdevice.h"
30#include "fimc-core.h" 31#include "fimc-core.h"
31 32
32static void fimc_capture_state_cleanup(struct fimc_dev *fimc) 33static void fimc_capture_state_cleanup(struct fimc_dev *fimc)
@@ -273,6 +274,31 @@ static struct vb2_ops fimc_capture_qops = {
273 .stop_streaming = stop_streaming, 274 .stop_streaming = stop_streaming,
274}; 275};
275 276
277/**
278 * fimc_capture_ctrls_create - initialize the control handler
279 * Initialize the capture video node control handler and fill it
280 * with the FIMC controls. Inherit any sensor's controls if the
281 * 'user_subdev_api' flag is false (default behaviour).
282 * This function need to be called with the graph mutex held.
283 */
284int fimc_capture_ctrls_create(struct fimc_dev *fimc)
285{
286 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
287 int ret;
288
289 if (WARN_ON(vid_cap->ctx == NULL))
290 return -ENXIO;
291 if (vid_cap->ctx->ctrls_rdy)
292 return 0;
293
294 ret = fimc_ctrls_create(vid_cap->ctx);
295 if (ret || vid_cap->user_subdev_api)
296 return ret;
297
298 return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
299 fimc->pipeline.sensor->ctrl_handler);
300}
301
276static int fimc_capture_open(struct file *file) 302static int fimc_capture_open(struct file *file)
277{ 303{
278 struct fimc_dev *fimc = video_drvdata(file); 304 struct fimc_dev *fimc = video_drvdata(file);
@@ -293,9 +319,10 @@ static int fimc_capture_open(struct file *file)
293 return ret; 319 return ret;
294 } 320 }
295 321
296 ++fimc->vid_cap.refcnt; 322 if (++fimc->vid_cap.refcnt == 1)
323 ret = fimc_capture_ctrls_create(fimc);
297 324
298 return 0; 325 return ret;
299} 326}
300 327
301static int fimc_capture_close(struct file *file) 328static int fimc_capture_close(struct file *file)
@@ -306,6 +333,7 @@ static int fimc_capture_close(struct file *file)
306 333
307 if (--fimc->vid_cap.refcnt == 0) { 334 if (--fimc->vid_cap.refcnt == 0) {
308 fimc_stop_capture(fimc); 335 fimc_stop_capture(fimc);
336 fimc_ctrls_delete(fimc->vid_cap.ctx);
309 vb2_queue_release(&fimc->vid_cap.vbq); 337 vb2_queue_release(&fimc->vid_cap.vbq);
310 } 338 }
311 339
@@ -546,30 +574,6 @@ static int fimc_cap_dqbuf(struct file *file, void *priv,
546 return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); 574 return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
547} 575}
548 576
549static int fimc_cap_s_ctrl(struct file *file, void *priv,
550 struct v4l2_control *ctrl)
551{
552 struct fimc_dev *fimc = video_drvdata(file);
553 struct fimc_ctx *ctx = fimc->vid_cap.ctx;
554 int ret = -EINVAL;
555
556 /* Allow any controls but 90/270 rotation while streaming */
557 if (!fimc_capture_active(ctx->fimc_dev) ||
558 ctrl->id != V4L2_CID_ROTATE ||
559 (ctrl->value != 90 && ctrl->value != 270)) {
560 ret = check_ctrl_val(ctx, ctrl);
561 if (!ret) {
562 ret = fimc_s_ctrl(ctx, ctrl);
563 if (!ret)
564 ctx->state |= FIMC_PARAMS;
565 }
566 }
567 if (ret == -EINVAL)
568 ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
569 core, s_ctrl, ctrl);
570 return ret;
571}
572
573static int fimc_cap_cropcap(struct file *file, void *fh, 577static int fimc_cap_cropcap(struct file *file, void *fh,
574 struct v4l2_cropcap *cr) 578 struct v4l2_cropcap *cr)
575{ 579{
@@ -656,10 +660,6 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
656 .vidioc_streamon = fimc_cap_streamon, 660 .vidioc_streamon = fimc_cap_streamon,
657 .vidioc_streamoff = fimc_cap_streamoff, 661 .vidioc_streamoff = fimc_cap_streamoff,
658 662
659 .vidioc_queryctrl = fimc_vidioc_queryctrl,
660 .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
661 .vidioc_s_ctrl = fimc_cap_s_ctrl,
662
663 .vidioc_g_crop = fimc_cap_g_crop, 663 .vidioc_g_crop = fimc_cap_g_crop,
664 .vidioc_s_crop = fimc_cap_s_crop, 664 .vidioc_s_crop = fimc_cap_s_crop,
665 .vidioc_cropcap = fimc_cap_cropcap, 665 .vidioc_cropcap = fimc_cap_cropcap,
@@ -743,6 +743,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
743 if (ret) 743 if (ret)
744 goto err_ent; 744 goto err_ent;
745 745
746 vfd->ctrl_handler = &ctx->ctrl_handler;
746 return 0; 747 return 0;
747 748
748err_ent: 749err_ent:
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index 3dab803e8054..c7ce93457a9b 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -162,43 +162,6 @@ static struct fimc_fmt fimc_formats[] = {
162 }, 162 },
163}; 163};
164 164
165static struct v4l2_queryctrl fimc_ctrls[] = {
166 {
167 .id = V4L2_CID_HFLIP,
168 .type = V4L2_CTRL_TYPE_BOOLEAN,
169 .name = "Horizontal flip",
170 .minimum = 0,
171 .maximum = 1,
172 .default_value = 0,
173 }, {
174 .id = V4L2_CID_VFLIP,
175 .type = V4L2_CTRL_TYPE_BOOLEAN,
176 .name = "Vertical flip",
177 .minimum = 0,
178 .maximum = 1,
179 .default_value = 0,
180 }, {
181 .id = V4L2_CID_ROTATE,
182 .type = V4L2_CTRL_TYPE_INTEGER,
183 .name = "Rotation (CCW)",
184 .minimum = 0,
185 .maximum = 270,
186 .step = 90,
187 .default_value = 0,
188 },
189};
190
191
192static struct v4l2_queryctrl *get_ctrl(int id)
193{
194 int i;
195
196 for (i = 0; i < ARRAY_SIZE(fimc_ctrls); ++i)
197 if (id == fimc_ctrls[i].id)
198 return &fimc_ctrls[i];
199 return NULL;
200}
201
202int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) 165int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot)
203{ 166{
204 int tx, ty; 167 int tx, ty;
@@ -777,6 +740,116 @@ static struct vb2_ops fimc_qops = {
777 .start_streaming = start_streaming, 740 .start_streaming = start_streaming,
778}; 741};
779 742
743/*
744 * V4L2 controls handling
745 */
746#define ctrl_to_ctx(__ctrl) \
747 container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
748
749static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
750{
751 struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
752 struct fimc_dev *fimc = ctx->fimc_dev;
753 struct samsung_fimc_variant *variant = fimc->variant;
754 unsigned long flags;
755 int ret = 0;
756
757 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
758 return 0;
759
760 switch (ctrl->id) {
761 case V4L2_CID_HFLIP:
762 spin_lock_irqsave(&ctx->slock, flags);
763 ctx->hflip = ctrl->val;
764 break;
765
766 case V4L2_CID_VFLIP:
767 spin_lock_irqsave(&ctx->slock, flags);
768 ctx->vflip = ctrl->val;
769 break;
770
771 case V4L2_CID_ROTATE:
772 if (fimc_capture_pending(fimc) ||
773 fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
774 ret = fimc_check_scaler_ratio(ctx->s_frame.width,
775 ctx->s_frame.height, ctx->d_frame.width,
776 ctx->d_frame.height, ctrl->val);
777 }
778 if (ret) {
779 v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
780 return -EINVAL;
781 }
782 if ((ctrl->val == 90 || ctrl->val == 270) &&
783 !variant->has_out_rot)
784 return -EINVAL;
785 spin_lock_irqsave(&ctx->slock, flags);
786 ctx->rotation = ctrl->val;
787 break;
788
789 default:
790 v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id);
791 return -EINVAL;
792 }
793 ctx->state |= FIMC_PARAMS;
794 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
795 spin_unlock_irqrestore(&ctx->slock, flags);
796 return 0;
797}
798
799static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
800 .s_ctrl = fimc_s_ctrl,
801};
802
803int fimc_ctrls_create(struct fimc_ctx *ctx)
804{
805 if (ctx->ctrls_rdy)
806 return 0;
807 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
808
809 ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
810 V4L2_CID_HFLIP, 0, 1, 1, 0);
811 ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
812 V4L2_CID_VFLIP, 0, 1, 1, 0);
813 ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
814 V4L2_CID_ROTATE, 0, 270, 90, 0);
815 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
816
817 return ctx->ctrl_handler.error;
818}
819
820void fimc_ctrls_delete(struct fimc_ctx *ctx)
821{
822 if (ctx->ctrls_rdy) {
823 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
824 ctx->ctrls_rdy = false;
825 }
826}
827
828void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
829{
830 if (!ctx->ctrls_rdy)
831 return;
832
833 mutex_lock(&ctx->ctrl_handler.lock);
834 v4l2_ctrl_activate(ctx->ctrl_rotate, active);
835 v4l2_ctrl_activate(ctx->ctrl_hflip, active);
836 v4l2_ctrl_activate(ctx->ctrl_vflip, active);
837
838 if (active) {
839 ctx->rotation = ctx->ctrl_rotate->val;
840 ctx->hflip = ctx->ctrl_hflip->val;
841 ctx->vflip = ctx->ctrl_vflip->val;
842 } else {
843 ctx->rotation = 0;
844 ctx->hflip = 0;
845 ctx->vflip = 0;
846 }
847 mutex_unlock(&ctx->ctrl_handler.lock);
848}
849
850/*
851 * V4L2 ioctl handlers
852 */
780static int fimc_m2m_querycap(struct file *file, void *fh, 853static int fimc_m2m_querycap(struct file *file, void *fh,
781 struct v4l2_capability *cap) 854 struct v4l2_capability *cap)
782{ 855{
@@ -1073,136 +1146,6 @@ static int fimc_m2m_streamoff(struct file *file, void *fh,
1073 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); 1146 return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
1074} 1147}
1075 1148
1076int fimc_vidioc_queryctrl(struct file *file, void *fh,
1077 struct v4l2_queryctrl *qc)
1078{
1079 struct fimc_ctx *ctx = fh_to_ctx(fh);
1080 struct fimc_dev *fimc = ctx->fimc_dev;
1081 struct v4l2_queryctrl *c;
1082 int ret = -EINVAL;
1083
1084 c = get_ctrl(qc->id);
1085 if (c) {
1086 *qc = *c;
1087 return 0;
1088 }
1089
1090 if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
1091 return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
1092 core, queryctrl, qc);
1093 }
1094 return ret;
1095}
1096
1097int fimc_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
1098{
1099 struct fimc_ctx *ctx = fh_to_ctx(fh);
1100 struct fimc_dev *fimc = ctx->fimc_dev;
1101
1102 switch (ctrl->id) {
1103 case V4L2_CID_HFLIP:
1104 ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0;
1105 break;
1106 case V4L2_CID_VFLIP:
1107 ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0;
1108 break;
1109 case V4L2_CID_ROTATE:
1110 ctrl->value = ctx->rotation;
1111 break;
1112 default:
1113 if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) {
1114 return v4l2_subdev_call(fimc->vid_cap.sd, core,
1115 g_ctrl, ctrl);
1116 } else {
1117 v4l2_err(fimc->m2m.vfd, "Invalid control\n");
1118 return -EINVAL;
1119 }
1120 }
1121 dbg("ctrl->value= %d", ctrl->value);
1122
1123 return 0;
1124}
1125
1126int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
1127{
1128 struct v4l2_queryctrl *c;
1129 c = get_ctrl(ctrl->id);
1130 if (!c)
1131 return -EINVAL;
1132
1133 if (ctrl->value < c->minimum || ctrl->value > c->maximum
1134 || (c->step != 0 && ctrl->value % c->step != 0)) {
1135 v4l2_err(ctx->fimc_dev->m2m.vfd, "Invalid control value\n");
1136 return -ERANGE;
1137 }
1138
1139 return 0;
1140}
1141
1142int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
1143{
1144 struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
1145 struct fimc_dev *fimc = ctx->fimc_dev;
1146 int ret = 0;
1147
1148 switch (ctrl->id) {
1149 case V4L2_CID_HFLIP:
1150 if (ctrl->value)
1151 ctx->flip |= FLIP_X_AXIS;
1152 else
1153 ctx->flip &= ~FLIP_X_AXIS;
1154 break;
1155
1156 case V4L2_CID_VFLIP:
1157 if (ctrl->value)
1158 ctx->flip |= FLIP_Y_AXIS;
1159 else
1160 ctx->flip &= ~FLIP_Y_AXIS;
1161 break;
1162
1163 case V4L2_CID_ROTATE:
1164 if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
1165 ret = fimc_check_scaler_ratio(ctx->s_frame.width,
1166 ctx->s_frame.height, ctx->d_frame.width,
1167 ctx->d_frame.height, ctrl->value);
1168 }
1169
1170 if (ret) {
1171 v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
1172 return -EINVAL;
1173 }
1174
1175 /* Check for the output rotator availability */
1176 if ((ctrl->value == 90 || ctrl->value == 270) &&
1177 (ctx->in_path == FIMC_DMA && !variant->has_out_rot))
1178 return -EINVAL;
1179 ctx->rotation = ctrl->value;
1180 break;
1181
1182 default:
1183 v4l2_err(fimc->v4l2_dev, "Invalid control\n");
1184 return -EINVAL;
1185 }
1186
1187 fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
1188
1189 return 0;
1190}
1191
1192static int fimc_m2m_s_ctrl(struct file *file, void *fh,
1193 struct v4l2_control *ctrl)
1194{
1195 struct fimc_ctx *ctx = fh_to_ctx(fh);
1196 int ret = 0;
1197
1198 ret = check_ctrl_val(ctx, ctrl);
1199 if (ret)
1200 return ret;
1201
1202 ret = fimc_s_ctrl(ctx, ctrl);
1203 return 0;
1204}
1205
1206static int fimc_m2m_cropcap(struct file *file, void *fh, 1149static int fimc_m2m_cropcap(struct file *file, void *fh,
1207 struct v4l2_cropcap *cr) 1150 struct v4l2_cropcap *cr)
1208{ 1151{
@@ -1368,10 +1311,6 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
1368 .vidioc_streamon = fimc_m2m_streamon, 1311 .vidioc_streamon = fimc_m2m_streamon,
1369 .vidioc_streamoff = fimc_m2m_streamoff, 1312 .vidioc_streamoff = fimc_m2m_streamoff,
1370 1313
1371 .vidioc_queryctrl = fimc_vidioc_queryctrl,
1372 .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
1373 .vidioc_s_ctrl = fimc_m2m_s_ctrl,
1374
1375 .vidioc_g_crop = fimc_m2m_g_crop, 1314 .vidioc_g_crop = fimc_m2m_g_crop,
1376 .vidioc_s_crop = fimc_m2m_s_crop, 1315 .vidioc_s_crop = fimc_m2m_s_crop,
1377 .vidioc_cropcap = fimc_m2m_cropcap 1316 .vidioc_cropcap = fimc_m2m_cropcap
@@ -1427,7 +1366,12 @@ static int fimc_m2m_open(struct file *file)
1427 if (!ctx) 1366 if (!ctx)
1428 return -ENOMEM; 1367 return -ENOMEM;
1429 v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); 1368 v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
1369 ret = fimc_ctrls_create(ctx);
1370 if (ret)
1371 goto error_fh;
1430 1372
1373 /* Use separate control handler per file handle */
1374 ctx->fh.ctrl_handler = &ctx->ctrl_handler;
1431 file->private_data = &ctx->fh; 1375 file->private_data = &ctx->fh;
1432 v4l2_fh_add(&ctx->fh); 1376 v4l2_fh_add(&ctx->fh);
1433 1377
@@ -1445,13 +1389,15 @@ static int fimc_m2m_open(struct file *file)
1445 ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); 1389 ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
1446 if (IS_ERR(ctx->m2m_ctx)) { 1390 if (IS_ERR(ctx->m2m_ctx)) {
1447 ret = PTR_ERR(ctx->m2m_ctx); 1391 ret = PTR_ERR(ctx->m2m_ctx);
1448 goto error_fh; 1392 goto error_c;
1449 } 1393 }
1450 1394
1451 if (fimc->m2m.refcnt++ == 0) 1395 if (fimc->m2m.refcnt++ == 0)
1452 set_bit(ST_M2M_RUN, &fimc->state); 1396 set_bit(ST_M2M_RUN, &fimc->state);
1453 return 0; 1397 return 0;
1454 1398
1399error_c:
1400 fimc_ctrls_delete(ctx);
1455error_fh: 1401error_fh:
1456 v4l2_fh_del(&ctx->fh); 1402 v4l2_fh_del(&ctx->fh);
1457 v4l2_fh_exit(&ctx->fh); 1403 v4l2_fh_exit(&ctx->fh);
@@ -1468,6 +1414,7 @@ static int fimc_m2m_release(struct file *file)
1468 task_pid_nr(current), fimc->state, fimc->m2m.refcnt); 1414 task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
1469 1415
1470 v4l2_m2m_ctx_release(ctx->m2m_ctx); 1416 v4l2_m2m_ctx_release(ctx->m2m_ctx);
1417 fimc_ctrls_delete(ctx);
1471 v4l2_fh_del(&ctx->fh); 1418 v4l2_fh_del(&ctx->fh);
1472 v4l2_fh_exit(&ctx->fh); 1419 v4l2_fh_exit(&ctx->fh);
1473 1420
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 22009fe6082d..1825e339fa35 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -20,6 +20,7 @@
20 20
21#include <media/media-entity.h> 21#include <media/media-entity.h>
22#include <media/videobuf2-core.h> 22#include <media/videobuf2-core.h>
23#include <media/v4l2-ctrls.h>
23#include <media/v4l2-device.h> 24#include <media/v4l2-device.h>
24#include <media/v4l2-mem2mem.h> 25#include <media/v4l2-mem2mem.h>
25#include <media/v4l2-mediabus.h> 26#include <media/v4l2-mediabus.h>
@@ -62,6 +63,7 @@ enum fimc_dev_flags {
62 ST_CAPT_STREAM, 63 ST_CAPT_STREAM,
63 ST_CAPT_SHUT, 64 ST_CAPT_SHUT,
64 ST_CAPT_BUSY, 65 ST_CAPT_BUSY,
66 ST_CAPT_APPLY_CFG,
65}; 67};
66 68
67#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) 69#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state)
@@ -128,11 +130,6 @@ enum fimc_color_fmt {
128/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ 130/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
129#define FIMC_COLOR_RANGE_NARROW (1 << 3) 131#define FIMC_COLOR_RANGE_NARROW (1 << 3)
130 132
131#define FLIP_NONE 0
132#define FLIP_X_AXIS 1
133#define FLIP_Y_AXIS 2
134#define FLIP_XY_AXIS (FLIP_X_AXIS | FLIP_Y_AXIS)
135
136/** 133/**
137 * struct fimc_fmt - the driver's internal color format data 134 * struct fimc_fmt - the driver's internal color format data
138 * @mbus_code: Media Bus pixel code, -1 if not applicable 135 * @mbus_code: Media Bus pixel code, -1 if not applicable
@@ -455,12 +452,18 @@ struct fimc_dev {
455 * @scaler: image scaler properties 452 * @scaler: image scaler properties
456 * @effect: image effect 453 * @effect: image effect
457 * @rotation: image clockwise rotation in degrees 454 * @rotation: image clockwise rotation in degrees
458 * @flip: image flip mode 455 * @hflip: indicates image horizontal flip if set
456 * @vflip: indicates image vertical flip if set
459 * @flags: additional flags for image conversion 457 * @flags: additional flags for image conversion
460 * @state: flags to keep track of user configuration 458 * @state: flags to keep track of user configuration
461 * @fimc_dev: the FIMC device this context applies to 459 * @fimc_dev: the FIMC device this context applies to
462 * @m2m_ctx: memory-to-memory device context 460 * @m2m_ctx: memory-to-memory device context
463 * @fh: v4l2 file handle 461 * @fh: v4l2 file handle
462 * @ctrl_handler: v4l2 controls handler
463 * @ctrl_rotate image rotation control
464 * @ctrl_hflip horizontal flip control
465 * @ctrl_vflip vartical flip control
466 * @ctrls_rdy: true if the control handler is initialized
464 */ 467 */
465struct fimc_ctx { 468struct fimc_ctx {
466 spinlock_t slock; 469 spinlock_t slock;
@@ -475,12 +478,18 @@ struct fimc_ctx {
475 struct fimc_scaler scaler; 478 struct fimc_scaler scaler;
476 struct fimc_effect effect; 479 struct fimc_effect effect;
477 int rotation; 480 int rotation;
478 u32 flip; 481 unsigned int hflip:1;
482 unsigned int vflip:1;
479 u32 flags; 483 u32 flags;
480 u32 state; 484 u32 state;
481 struct fimc_dev *fimc_dev; 485 struct fimc_dev *fimc_dev;
482 struct v4l2_m2m_ctx *m2m_ctx; 486 struct v4l2_m2m_ctx *m2m_ctx;
483 struct v4l2_fh fh; 487 struct v4l2_fh fh;
488 struct v4l2_ctrl_handler ctrl_handler;
489 struct v4l2_ctrl *ctrl_rotate;
490 struct v4l2_ctrl *ctrl_hflip;
491 struct v4l2_ctrl *ctrl_vflip;
492 bool ctrls_rdy;
484}; 493};
485 494
486#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) 495#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
@@ -636,15 +645,11 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
636/* fimc-core.c */ 645/* fimc-core.c */
637int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, 646int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
638 struct v4l2_fmtdesc *f); 647 struct v4l2_fmtdesc *f);
639int fimc_vidioc_queryctrl(struct file *file, void *priv,
640 struct v4l2_queryctrl *qc);
641int fimc_vidioc_g_ctrl(struct file *file, void *priv,
642 struct v4l2_control *ctrl);
643
644int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f); 648int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f);
645int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr); 649int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
646int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl); 650int fimc_ctrls_create(struct fimc_ctx *ctx);
647int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl); 651void fimc_ctrls_delete(struct fimc_ctx *ctx);
652void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
648int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); 653int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f);
649 654
650struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); 655struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
@@ -667,6 +672,7 @@ void fimc_unregister_driver(void);
667int fimc_register_capture_device(struct fimc_dev *fimc, 672int fimc_register_capture_device(struct fimc_dev *fimc,
668 struct v4l2_device *v4l2_dev); 673 struct v4l2_device *v4l2_dev);
669void fimc_unregister_capture_device(struct fimc_dev *fimc); 674void fimc_unregister_capture_device(struct fimc_dev *fimc);
675int fimc_capture_ctrls_create(struct fimc_dev *fimc);
670int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, 676int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
671 struct fimc_vid_buffer *fimc_vb); 677 struct fimc_vid_buffer *fimc_vb);
672int fimc_capture_suspend(struct fimc_dev *fimc); 678int fimc_capture_suspend(struct fimc_dev *fimc);
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 50f3fcaa4e77..13ce2a43027c 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -22,6 +22,7 @@
22#include <linux/types.h> 22#include <linux/types.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/version.h> 24#include <linux/version.h>
25#include <media/v4l2-ctrls.h>
25#include <media/media-device.h> 26#include <media/media-device.h>
26 27
27#include "fimc-core.h" 28#include "fimc-core.h"
@@ -649,15 +650,23 @@ static int fimc_md_link_notify(struct media_pad *source,
649 ret = __fimc_pipeline_shutdown(fimc); 650 ret = __fimc_pipeline_shutdown(fimc);
650 fimc->pipeline.sensor = NULL; 651 fimc->pipeline.sensor = NULL;
651 fimc->pipeline.csis = NULL; 652 fimc->pipeline.csis = NULL;
653
654 mutex_lock(&fimc->lock);
655 fimc_ctrls_delete(fimc->vid_cap.ctx);
656 mutex_unlock(&fimc->lock);
652 return ret; 657 return ret;
653 } 658 }
654 /* 659 /*
655 * Link activation. Enable power of pipeline elements only if the 660 * Link activation. Enable power of pipeline elements only if the
656 * pipeline is already in use, i.e. its video node is opened. 661 * pipeline is already in use, i.e. its video node is opened.
662 * Recreate the controls destroyed during the link deactivation.
657 */ 663 */
658 mutex_lock(&fimc->lock); 664 mutex_lock(&fimc->lock);
659 if (fimc->vid_cap.refcnt > 0) 665 if (fimc->vid_cap.refcnt > 0) {
660 ret = __fimc_pipeline_initialize(fimc, source->entity, true); 666 ret = __fimc_pipeline_initialize(fimc, source->entity, true);
667 if (!ret)
668 ret = fimc_capture_ctrls_create(fimc);
669 }
661 mutex_unlock(&fimc->lock); 670 mutex_unlock(&fimc->lock);
662 671
663 return ret ? -EPIPE : ret; 672 return ret ? -EPIPE : ret;
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index c6882636ea94..50937b40854f 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -41,19 +41,11 @@ static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
41{ 41{
42 u32 flip = S5P_MSCTRL_FLIP_NORMAL; 42 u32 flip = S5P_MSCTRL_FLIP_NORMAL;
43 43
44 switch (ctx->flip) { 44 if (ctx->hflip)
45 case FLIP_X_AXIS:
46 flip = S5P_MSCTRL_FLIP_X_MIRROR; 45 flip = S5P_MSCTRL_FLIP_X_MIRROR;
47 break; 46 if (ctx->vflip)
48 case FLIP_Y_AXIS:
49 flip = S5P_MSCTRL_FLIP_Y_MIRROR; 47 flip = S5P_MSCTRL_FLIP_Y_MIRROR;
50 break; 48
51 case FLIP_XY_AXIS:
52 flip = S5P_MSCTRL_FLIP_180;
53 break;
54 default:
55 break;
56 }
57 if (ctx->rotation <= 90) 49 if (ctx->rotation <= 90)
58 return flip; 50 return flip;
59 51
@@ -64,19 +56,11 @@ static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
64{ 56{
65 u32 flip = S5P_CITRGFMT_FLIP_NORMAL; 57 u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
66 58
67 switch (ctx->flip) { 59 if (ctx->hflip)
68 case FLIP_X_AXIS: 60 flip |= S5P_CITRGFMT_FLIP_X_MIRROR;
69 flip = S5P_CITRGFMT_FLIP_X_MIRROR; 61 if (ctx->vflip)
70 break; 62 flip |= S5P_CITRGFMT_FLIP_Y_MIRROR;
71 case FLIP_Y_AXIS: 63
72 flip = S5P_CITRGFMT_FLIP_Y_MIRROR;
73 break;
74 case FLIP_XY_AXIS:
75 flip = S5P_CITRGFMT_FLIP_180;
76 break;
77 default:
78 break;
79 }
80 if (ctx->rotation <= 90) 64 if (ctx->rotation <= 90)
81 return flip; 65 return flip;
82 66