Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfea0019 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] mt9p031: Implement black level compensation control



Add four new controls to configure black level compensation (BLC):

- V4L2_CID_BLC_AUTO selects between manual and auto BLC
- V4L2_CID_BLC_TARGET_LEVEL sets the target level for auto BLC
- V4L2_CID_BLC_ANALOG_OFFSET sets the analog offset for manual BLC
- V4L2_CID_BLC_DIGITAL_OFFSET sets the digital offset for manual BLC

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 15693b57
Loading
Loading
Loading
Loading
+111 −7
Original line number Diff line number Diff line
@@ -91,7 +91,14 @@
#define		MT9P031_GLOBAL_GAIN_MAX			1024
#define		MT9P031_GLOBAL_GAIN_DEF			8
#define		MT9P031_GLOBAL_GAIN_MULT		(1 << 6)
#define MT9P031_ROW_BLACK_TARGET			0x49
#define MT9P031_ROW_BLACK_DEF_OFFSET			0x4b
#define MT9P031_GREEN1_OFFSET				0x60
#define MT9P031_GREEN2_OFFSET				0x61
#define MT9P031_BLACK_LEVEL_CALIBRATION			0x62
#define		MT9P031_BLC_MANUAL_BLC			(1 << 0)
#define MT9P031_RED_OFFSET				0x63
#define MT9P031_BLUE_OFFSET				0x64
#define MT9P031_TEST_PATTERN				0xa0
#define		MT9P031_TEST_PATTERN_SHIFT		3
#define		MT9P031_TEST_PATTERN_ENABLE		(1 << 0)
@@ -110,7 +117,6 @@ struct mt9p031 {
	struct media_pad pad;
	struct v4l2_rect crop;  /* Sensor window */
	struct v4l2_mbus_framefmt format;
	struct v4l2_ctrl_handler ctrls;
	struct mt9p031_platform_data *pdata;
	struct mutex power_lock; /* lock to protect power_count */
	int power_count;
@@ -119,6 +125,10 @@ struct mt9p031 {
	struct aptina_pll pll;
	int reset;

	struct v4l2_ctrl_handler ctrls;
	struct v4l2_ctrl *blc_auto;
	struct v4l2_ctrl *blc_offset;

	/* Registers cache */
	u16 output_control;
	u16 mode2;
@@ -565,6 +575,10 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
 */

#define V4L2_CID_TEST_PATTERN		(V4L2_CID_USER_BASE | 0x1001)
#define V4L2_CID_BLC_AUTO		(V4L2_CID_USER_BASE | 0x1002)
#define V4L2_CID_BLC_TARGET_LEVEL	(V4L2_CID_USER_BASE | 0x1003)
#define V4L2_CID_BLC_ANALOG_OFFSET	(V4L2_CID_USER_BASE | 0x1004)
#define V4L2_CID_BLC_DIGITAL_OFFSET	(V4L2_CID_USER_BASE | 0x1005)

static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
{
@@ -629,11 +643,17 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)

	case V4L2_CID_TEST_PATTERN:
		if (!ctrl->val) {
			ret = mt9p031_set_mode2(mt9p031,
					0, MT9P031_READ_MODE_2_ROW_BLC);
			/* Restore the black level compensation settings. */
			if (mt9p031->blc_auto->cur.val != 0) {
				ret = mt9p031_s_ctrl(mt9p031->blc_auto);
				if (ret < 0)
					return ret;

			}
			if (mt9p031->blc_offset->cur.val != 0) {
				ret = mt9p031_s_ctrl(mt9p031->blc_offset);
				if (ret < 0)
					return ret;
			}
			return mt9p031_write(client, MT9P031_TEST_PATTERN,
					     MT9P031_TEST_PATTERN_DISABLE);
		}
@@ -648,10 +668,14 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
		if (ret < 0)
			return ret;

		/* Disable digital black level compensation when using a test
		 * pattern.
		 */
		ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
					0);
		if (ret < 0)
			return ret;

		ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
		if (ret < 0)
			return ret;
@@ -659,7 +683,40 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
		return mt9p031_write(client, MT9P031_TEST_PATTERN,
				((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
				| MT9P031_TEST_PATTERN_ENABLE);

	case V4L2_CID_BLC_AUTO:
		ret = mt9p031_set_mode2(mt9p031,
				ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
				ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
		if (ret < 0)
			return ret;

		return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
				     ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);

	case V4L2_CID_BLC_TARGET_LEVEL:
		return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
				     ctrl->val);

	case V4L2_CID_BLC_ANALOG_OFFSET:
		data = ctrl->val & ((1 << 9) - 1);

		ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
		if (ret < 0)
			return ret;
		ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
		if (ret < 0)
			return ret;
		ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
		if (ret < 0)
			return ret;
		return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);

	case V4L2_CID_BLC_DIGITAL_OFFSET:
		return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
				     ctrl->val & ((1 << 12) - 1));
	}

	return 0;
}

@@ -693,6 +750,46 @@ static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
		.flags		= 0,
		.menu_skip_mask	= 0,
		.qmenu		= mt9p031_test_pattern_menu,
	}, {
		.ops		= &mt9p031_ctrl_ops,
		.id		= V4L2_CID_BLC_AUTO,
		.type		= V4L2_CTRL_TYPE_BOOLEAN,
		.name		= "BLC, Auto",
		.min		= 0,
		.max		= 1,
		.step		= 1,
		.def		= 1,
		.flags		= 0,
	}, {
		.ops		= &mt9p031_ctrl_ops,
		.id		= V4L2_CID_BLC_TARGET_LEVEL,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.name		= "BLC Target Level",
		.min		= 0,
		.max		= 4095,
		.step		= 1,
		.def		= 168,
		.flags		= 0,
	}, {
		.ops		= &mt9p031_ctrl_ops,
		.id		= V4L2_CID_BLC_ANALOG_OFFSET,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.name		= "BLC Analog Offset",
		.min		= -255,
		.max		= 255,
		.step		= 1,
		.def		= 32,
		.flags		= 0,
	}, {
		.ops		= &mt9p031_ctrl_ops,
		.id		= V4L2_CID_BLC_DIGITAL_OFFSET,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.name		= "BLC Digital Offset",
		.min		= -2048,
		.max		= 2047,
		.step		= 1,
		.def		= 40,
		.flags		= 0,
	}
};

@@ -872,9 +969,16 @@ static int mt9p031_probe(struct i2c_client *client,

	mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;

	if (mt9p031->ctrls.error)
	if (mt9p031->ctrls.error) {
		printk(KERN_INFO "%s: control initialization error %d\n",
		       __func__, mt9p031->ctrls.error);
		ret = mt9p031->ctrls.error;
		goto done;
	}

	mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
	mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
					     V4L2_CID_BLC_DIGITAL_OFFSET);

	mutex_init(&mt9p031->power_lock);
	v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);