@@ -84,6 +84,25 @@
#define NUM_MODE_REGS 187
#define NUM_MODE_REGS_2 200
+/* Flip Mirror Controls from sensor */
+#define OV8856_REG_FORMAT1 0x3820
+#define OV8856_REG_FORMAT2 0x3821
+#define OV8856_REG_FORMAT1_OP_1 BIT(1)
+#define OV8856_REG_FORMAT1_OP_2 BIT(2)
+#define OV8856_REG_FORMAT1_OP_3 BIT(6)
+#define OV8856_REG_FORMAT2_OP_1 BIT(1)
+#define OV8856_REG_FORMAT2_OP_2 BIT(2)
+#define OV8856_REG_FORMAT2_OP_3 BIT(6)
+#define OV8856_REG_FLIP_OPT_1 0x376b
+#define OV8856_REG_FLIP_OPT_2 0x5001
+#define OV8856_REG_FLIP_OPT_3 0x502e
+#define OV8856_REG_MIRROR_OPT_1 0x5004
+#define OV8856_REG_FLIP_OP_0 BIT(0)
+#define OV8856_REG_FLIP_OP_1 BIT(1)
+#define OV8856_REG_FLIP_OP_2 BIT(2)
+#define OV8856_REG_MIRROR_OP_1 BIT(1)
+#define OV8856_REG_MIRROR_OP_2 BIT(2)
+
#define to_ov8856(_sd) container_of(_sd, struct ov8856, sd)
static const char * const ov8856_supply_names[] = {
@@ -1661,6 +1680,93 @@ static int ov8856_test_pattern(struct ov8856 *ov8856, u32 pattern)
OV8856_REG_VALUE_08BIT, pattern);
}
+static int ov8856_set_ctrl_hflip(struct ov8856 *ov8856, u32 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_MIRROR_OPT_1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_MIRROR_OP_2 :
+ val | OV8856_REG_MIRROR_OP_2);
+
+ if (ret)
+ return ret;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT2,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov8856_write_reg(ov8856, OV8856_REG_FORMAT2,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_FORMAT2_OP_1 &
+ ~OV8856_REG_FORMAT2_OP_2 &
+ ~OV8856_REG_FORMAT2_OP_3 :
+ val | OV8856_REG_FORMAT2_OP_1 |
+ OV8856_REG_FORMAT2_OP_2 |
+ OV8856_REG_FORMAT2_OP_3);
+}
+
+static int ov8856_set_ctrl_vflip(struct ov8856 *ov8856, u8 ctrl_val)
+{
+ int ret;
+ u32 val;
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FLIP_OP_1 |
+ OV8856_REG_FLIP_OP_2 :
+ val & ~OV8856_REG_FLIP_OP_1 &
+ ~OV8856_REG_FLIP_OP_2);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_2,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FLIP_OP_2 :
+ val & ~OV8856_REG_FLIP_OP_2);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ ret = ov8856_write_reg(ov8856, OV8856_REG_FLIP_OPT_3,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val & ~OV8856_REG_FLIP_OP_0 &
+ ~OV8856_REG_FLIP_OP_1 :
+ val | OV8856_REG_FLIP_OP_0 |
+ OV8856_REG_FLIP_OP_1);
+
+ ret = ov8856_read_reg(ov8856, OV8856_REG_FORMAT1,
+ OV8856_REG_VALUE_08BIT, &val);
+ if (ret)
+ return ret;
+
+ return ov8856_write_reg(ov8856, OV8856_REG_FORMAT1,
+ OV8856_REG_VALUE_08BIT,
+ ctrl_val ? val | OV8856_REG_FORMAT1_OP_1 |
+ OV8856_REG_FORMAT1_OP_3 |
+ OV8856_REG_FORMAT1_OP_2 :
+ val & ~OV8856_REG_FORMAT1_OP_1 &
+ ~OV8856_REG_FORMAT1_OP_3 &
+ ~OV8856_REG_FORMAT1_OP_2);
+}
+
static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov8856 *ov8856 = container_of(ctrl->handler,
@@ -1710,6 +1816,14 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov8856_test_pattern(ov8856, ctrl->val);
break;
+ case V4L2_CID_HFLIP:
+ ret = ov8856_set_ctrl_hflip(ov8856, ctrl->val);
+ break;
+
+ case V4L2_CID_VFLIP:
+ ret = ov8856_set_ctrl_vflip(ov8856, ctrl->val);
+ break;
+
default:
ret = -EINVAL;
break;
@@ -1786,6 +1900,10 @@ static int ov8856_init_controls(struct ov8856 *ov8856)
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov8856_test_pattern_menu) - 1,
0, 0, ov8856_test_pattern_menu);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
if (ctrl_hdlr->error)
return ctrl_hdlr->error;