Commit c19b93a6 authored by Shawn Tu's avatar Shawn Tu Committed by Mauro Carvalho Chehab
Browse files

media: ov8856: add vflip/hflip control support



Add V4L2 controls: horizontal/vertical flip,
keep SGRBG10 Bayer order output (via change v/hflip)

Signed-off-by: default avatarShawn Tu <shawnx.tu@intel.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent c492ec9a
Loading
Loading
Loading
Loading
+118 −0
Original line number Diff line number Diff line
@@ -80,6 +80,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[] = {
@@ -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;