OSDN Git Service

media: ov8856: add vflip/hflip control support
authorShawn Tu <shawnx.tu@intel.com>
Fri, 16 Apr 2021 09:58:59 +0000 (11:58 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Wed, 2 Jun 2021 09:55:04 +0000 (11:55 +0200)
Add V4L2 controls: horizontal/vertical flip,
keep SGRBG10 Bayer order output (via change v/hflip)

Signed-off-by: Shawn Tu <shawnx.tu@intel.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/i2c/ov8856.c

index d145f00..a6bc665 100644 (file)
 #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[] = {
@@ -1653,6 +1672,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,
@@ -1702,6 +1808,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;
@@ -1778,6 +1892,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;