Commit a5826484 authored by Akinobu Mita's avatar Akinobu Mita Committed by Mauro Carvalho Chehab
Browse files

media: mt9m001: introduce multi_reg_write()



Introduce multi_reg_write() to write multiple registers to the device and
use it where possible.

Cc: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 1e57e4ce
Loading
Loading
Loading
Loading
+57 −31
Original line number Diff line number Diff line
@@ -47,6 +47,8 @@
#define MT9M001_MIN_HEIGHT		32
#define MT9M001_COLUMN_SKIP		20
#define MT9M001_ROW_SKIP		12
#define MT9M001_DEFAULT_HBLANK		9
#define MT9M001_DEFAULT_VBLANK		25

/* MT9M001 has only one fixed colorspace per pixelcode */
struct mt9m001_datafmt {
@@ -137,25 +139,65 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
	return reg_write(client, reg, ret & ~data);
}

struct mt9m001_reg {
	u8 reg;
	u16 data;
};

static int multi_reg_write(struct i2c_client *client,
			   const struct mt9m001_reg *regs, int num)
{
	int i;

	for (i = 0; i < num; i++) {
		int ret = reg_write(client, regs[i].reg, regs[i].data);

		if (ret)
			return ret;
	}

	return 0;
}

static int mt9m001_init(struct i2c_client *client)
{
	int ret;
	const struct mt9m001_reg init_regs[] = {
		/*
		 * Issue a soft reset. This returns all registers to their
		 * default values.
		 */
		{ MT9M001_RESET, 1 },
		{ MT9M001_RESET, 0 },
		/* Disable chip, synchronous option update */
		{ MT9M001_OUTPUT_CONTROL, 0 }
	};

	dev_dbg(&client->dev, "%s\n", __func__);

	return multi_reg_write(client, init_regs, ARRAY_SIZE(init_regs));
}

static int mt9m001_apply_selection(struct v4l2_subdev *sd,
				    struct v4l2_rect *rect)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct mt9m001 *mt9m001 = to_mt9m001(client);
	const struct mt9m001_reg regs[] = {
		/* Blanking and start values - default... */
		{ MT9M001_HORIZONTAL_BLANKING, MT9M001_DEFAULT_HBLANK },
		{ MT9M001_VERTICAL_BLANKING, MT9M001_DEFAULT_VBLANK },
		/*
	 * We don't know, whether platform provides reset, issue a soft reset
	 * too. This returns all registers to their default values.
		 * The caller provides a supported format, as verified per
		 * call to .set_fmt(FORMAT_TRY).
		 */
	ret = reg_write(client, MT9M001_RESET, 1);
	if (!ret)
		ret = reg_write(client, MT9M001_RESET, 0);

	/* Disable chip, synchronous option update */
	if (!ret)
		ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
		{ MT9M001_COLUMN_START, rect->left },
		{ MT9M001_ROW_START, rect->top },
		{ MT9M001_WINDOW_WIDTH, rect->width - 1 },
		{ MT9M001_WINDOW_HEIGHT,
			rect->height + mt9m001->y_skip_top - 1 },
	};

	return ret;
	return multi_reg_write(client, regs, ARRAY_SIZE(regs));
}

static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
@@ -175,7 +217,6 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd,
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct mt9m001 *mt9m001 = to_mt9m001(client);
	struct v4l2_rect rect = sel->r;
	const u16 hblank = 9, vblank = 25;
	int ret;

	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
@@ -199,26 +240,11 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd,
	soc_camera_limit_side(&rect.top, &rect.height,
		     MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);

	mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
	mt9m001->total_h = rect.height + mt9m001->y_skip_top +
			   MT9M001_DEFAULT_VBLANK;

	/* Blanking and start values - default... */
	ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
	if (!ret)
		ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);

	/*
	 * The caller provides a supported format, as verified per
	 * call to .set_fmt(FORMAT_TRY).
	 */
	if (!ret)
		ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
	if (!ret)
		ret = reg_write(client, MT9M001_ROW_START, rect.top);
	if (!ret)
		ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
	if (!ret)
		ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
				rect.height + mt9m001->y_skip_top - 1);
	ret = mt9m001_apply_selection(sd, &rect);
	if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
		ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);