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: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Akinobu Mita 2019-01-08 12:51:43 -02:00 committed by Mauro Carvalho Chehab
parent 1e57e4ce90
commit a5826484d4

View File

@ -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__);
/*
* We don't know, whether platform provides reset, issue a soft reset
* too. This returns all registers to their default values.
*/
ret = reg_write(client, MT9M001_RESET, 1);
if (!ret)
ret = reg_write(client, MT9M001_RESET, 0);
return multi_reg_write(client, init_regs, ARRAY_SIZE(init_regs));
}
/* Disable chip, synchronous option update */
if (!ret)
ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
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 },
/*
* The caller provides a supported format, as verified per
* call to .set_fmt(FORMAT_TRY).
*/
{ 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);