|
@@ -22,6 +22,7 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/v4l2-mediabus.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
+#include <media/v4l2-ctrls.h>
|
|
|
#include <media/v4l2-subdev.h>
|
|
|
#include <media/v4l2-tpg.h>
|
|
|
|
|
@@ -38,6 +39,7 @@ struct vimc_sen_device {
|
|
|
u8 *frame;
|
|
|
/* The active format */
|
|
|
struct v4l2_mbus_framefmt mbus_format;
|
|
|
+ struct v4l2_ctrl_handler hdl;
|
|
|
};
|
|
|
|
|
|
static const struct v4l2_mbus_framefmt fmt_default = {
|
|
@@ -291,6 +293,31 @@ static const struct v4l2_subdev_ops vimc_sen_ops = {
|
|
|
.video = &vimc_sen_video_ops,
|
|
|
};
|
|
|
|
|
|
+static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
|
+{
|
|
|
+ struct vimc_sen_device *vsen =
|
|
|
+ container_of(ctrl->handler, struct vimc_sen_device, hdl);
|
|
|
+
|
|
|
+ switch (ctrl->id) {
|
|
|
+ case VIMC_CID_TEST_PATTERN:
|
|
|
+ tpg_s_pattern(&vsen->tpg, ctrl->val);
|
|
|
+ break;
|
|
|
+ case V4L2_CID_HFLIP:
|
|
|
+ tpg_s_hflip(&vsen->tpg, ctrl->val);
|
|
|
+ break;
|
|
|
+ case V4L2_CID_VFLIP:
|
|
|
+ tpg_s_vflip(&vsen->tpg, ctrl->val);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = {
|
|
|
+ .s_ctrl = vimc_sen_s_ctrl,
|
|
|
+};
|
|
|
+
|
|
|
static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
|
|
|
void *master_data)
|
|
|
{
|
|
@@ -299,10 +326,28 @@ static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
|
|
|
container_of(ved, struct vimc_sen_device, ved);
|
|
|
|
|
|
vimc_ent_sd_unregister(ved, &vsen->sd);
|
|
|
+ v4l2_ctrl_handler_free(&vsen->hdl);
|
|
|
tpg_free(&vsen->tpg);
|
|
|
kfree(vsen);
|
|
|
}
|
|
|
|
|
|
+/* Image Processing Controls */
|
|
|
+static const struct v4l2_ctrl_config vimc_sen_ctrl_class = {
|
|
|
+ .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
|
|
|
+ .id = VIMC_CID_VIMC_CLASS,
|
|
|
+ .name = "VIMC Controls",
|
|
|
+ .type = V4L2_CTRL_TYPE_CTRL_CLASS,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = {
|
|
|
+ .ops = &vimc_sen_ctrl_ops,
|
|
|
+ .id = VIMC_CID_TEST_PATTERN,
|
|
|
+ .name = "Test Pattern",
|
|
|
+ .type = V4L2_CTRL_TYPE_MENU,
|
|
|
+ .max = TPG_PAT_NOISE,
|
|
|
+ .qmenu = tpg_pattern_strings,
|
|
|
+};
|
|
|
+
|
|
|
static int vimc_sen_comp_bind(struct device *comp, struct device *master,
|
|
|
void *master_data)
|
|
|
{
|
|
@@ -316,6 +361,20 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
|
|
|
if (!vsen)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
+ v4l2_ctrl_handler_init(&vsen->hdl, 4);
|
|
|
+
|
|
|
+ v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL);
|
|
|
+ v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL);
|
|
|
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
|
|
|
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
|
|
|
+ v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
|
|
|
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
|
|
|
+ vsen->sd.ctrl_handler = &vsen->hdl;
|
|
|
+ if (vsen->hdl.error) {
|
|
|
+ ret = vsen->hdl.error;
|
|
|
+ goto err_free_vsen;
|
|
|
+ }
|
|
|
+
|
|
|
/* Initialize ved and sd */
|
|
|
ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev,
|
|
|
pdata->entity_name,
|
|
@@ -323,7 +382,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
|
|
|
(const unsigned long[1]) {MEDIA_PAD_FL_SOURCE},
|
|
|
&vimc_sen_ops);
|
|
|
if (ret)
|
|
|
- goto err_free_vsen;
|
|
|
+ goto err_free_hdl;
|
|
|
|
|
|
dev_set_drvdata(comp, &vsen->ved);
|
|
|
vsen->dev = comp;
|
|
@@ -342,6 +401,8 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
|
|
|
|
|
|
err_unregister_ent_sd:
|
|
|
vimc_ent_sd_unregister(&vsen->ved, &vsen->sd);
|
|
|
+err_free_hdl:
|
|
|
+ v4l2_ctrl_handler_free(&vsen->hdl);
|
|
|
err_free_vsen:
|
|
|
kfree(vsen);
|
|
|
|