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

Commit 96c75399 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (12536): soc-camera: remove .gain and .exposure struct soc_camera_device members



This makes the soc-camera interface for V4L2 subdevices thinner yet. Handle
gain and exposure internally in each driver just like all other controls.

Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a4c56fd8
Loading
Loading
Loading
Loading
+28 −15
Original line number Diff line number Diff line
@@ -80,6 +80,8 @@ struct mt9m001 {
	struct v4l2_rect rect;	/* Sensor window */
	__u32 fourcc;
	int model;	/* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
	unsigned int gain;
	unsigned int exposure;
	unsigned char autoexposure;
};

@@ -129,8 +131,8 @@ static int mt9m001_init(struct i2c_client *client)
	dev_dbg(&client->dev, "%s\n", __func__);

	/*
	 * We don't know, whether platform provides reset,
	 * issue a soft reset too
	 * 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)
@@ -200,6 +202,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
	struct soc_camera_device *icd = client->dev.platform_data;
	int ret;
	const u16 hblank = 9, vblank = 25;
	unsigned int total_h;

	if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 ||
	    mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16)
@@ -219,6 +222,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
	soc_camera_limit_side(&rect.top, &rect.height,
		     MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);

	total_h = rect.height + icd->y_skip_top + vblank;

	/* Blanking and start values - default... */
	ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
	if (!ret)
@@ -236,14 +241,12 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
		ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
				rect.height + icd->y_skip_top - 1);
	if (!ret && mt9m001->autoexposure) {
		ret = reg_write(client, MT9M001_SHUTTER_WIDTH,
				rect.height + icd->y_skip_top + vblank);
		ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h);
		if (!ret) {
			const struct v4l2_queryctrl *qctrl =
				soc_camera_find_qctrl(icd->ops,
						      V4L2_CID_EXPOSURE);
			icd->exposure = (524 + (rect.height + icd->y_skip_top +
						vblank - 1) *
			mt9m001->exposure = (524 + (total_h - 1) *
				 (qctrl->maximum - qctrl->minimum)) /
				1048 + qctrl->minimum;
		}
@@ -457,6 +460,12 @@ static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
	case V4L2_CID_EXPOSURE_AUTO:
		ctrl->value = mt9m001->autoexposure;
		break;
	case V4L2_CID_GAIN:
		ctrl->value = mt9m001->gain;
		break;
	case V4L2_CID_EXPOSURE:
		ctrl->value = mt9m001->exposure;
		break;
	}
	return 0;
}
@@ -518,7 +527,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
		}

		/* Success */
		icd->gain = ctrl->value;
		mt9m001->gain = ctrl->value;
		break;
	case V4L2_CID_EXPOSURE:
		/* mt9m001 has maximum == default */
@@ -535,20 +544,20 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
				shutter);
			if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
				return -EIO;
			icd->exposure = ctrl->value;
			mt9m001->exposure = ctrl->value;
			mt9m001->autoexposure = 0;
		}
		break;
	case V4L2_CID_EXPOSURE_AUTO:
		if (ctrl->value) {
			const u16 vblank = 25;
			unsigned int total_h = mt9m001->rect.height +
				icd->y_skip_top + vblank;
			if (reg_write(client, MT9M001_SHUTTER_WIDTH,
				      mt9m001->rect.height +
				      icd->y_skip_top + vblank) < 0)
				      total_h) < 0)
				return -EIO;
			qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
			icd->exposure = (524 + (mt9m001->rect.height +
						icd->y_skip_top + vblank - 1) *
			mt9m001->exposure = (524 + (total_h - 1) *
				 (qctrl->maximum - qctrl->minimum)) /
				1048 + qctrl->minimum;
			mt9m001->autoexposure = 1;
@@ -629,6 +638,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
	if (ret < 0)
		dev_err(&client->dev, "Failed to initialise the camera\n");

	/* mt9m001_init() has reset the chip, returning registers to defaults */
	mt9m001->gain = 64;
	mt9m001->exposure = 255;

	return ret;
}

@@ -701,7 +714,7 @@ static int mt9m001_probe(struct i2c_client *client,

	/* Second stage probe - when a capture adapter is there */
	icd->ops		= &mt9m001_ops;
	icd->y_skip_top		= 1;
	icd->y_skip_top		= 0;

	mt9m001->rect.left	= MT9M001_COLUMN_SKIP;
	mt9m001->rect.top	= MT9M001_ROW_SKIP;
+21 −8
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@ struct mt9m111 {
	enum mt9m111_context context;
	struct v4l2_rect rect;
	u32 pixfmt;
	unsigned int gain;
	unsigned char autoexposure;
	unsigned char datawidth;
	unsigned int powered:1;
@@ -513,7 +514,8 @@ static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt)
		ret = mt9m111_setfmt_yuv(client);
		break;
	default:
		dev_err(&client->dev, "Pixel format not handled : %x\n", pixfmt);
		dev_err(&client->dev, "Pixel format not handled : %x\n",
			pixfmt);
		ret = -EINVAL;
	}

@@ -536,9 +538,9 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
	};
	int ret;

	dev_dbg(&client->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n",
		__func__, pix->pixelformat, rect.left, rect.top, rect.width,
		rect.height);
	dev_dbg(&client->dev,
		"%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
		pix->pixelformat, rect.left, rect.top, rect.width, rect.height);

	ret = mt9m111_make_rect(client, &rect);
	if (!ret)
@@ -672,8 +674,10 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
};

static int mt9m111_resume(struct soc_camera_device *icd);
static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);

static struct soc_camera_ops mt9m111_ops = {
	.suspend		= mt9m111_suspend,
	.resume			= mt9m111_resume,
	.query_bus_param	= mt9m111_query_bus_param,
	.set_bus_param		= mt9m111_set_bus_param,
@@ -714,13 +718,13 @@ static int mt9m111_get_global_gain(struct i2c_client *client)

static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
{
	struct soc_camera_device *icd = client->dev.platform_data;
	struct mt9m111 *mt9m111 = to_mt9m111(client);
	u16 val;

	if (gain > 63 * 2 * 2)
		return -EINVAL;

	icd->gain = gain;
	mt9m111->gain = gain;
	if ((gain >= 64 * 2) && (gain < 63 * 2 * 2))
		val = (1 << 10) | (1 << 9) | (gain / 4);
	else if ((gain >= 64) && (gain < 64 * 2))
@@ -844,17 +848,26 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
	return ret;
}

static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
{
	struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
	struct mt9m111 *mt9m111 = to_mt9m111(client);

	mt9m111->gain = mt9m111_get_global_gain(client);

	return 0;
}

static int mt9m111_restore_state(struct i2c_client *client)
{
	struct mt9m111 *mt9m111 = to_mt9m111(client);
	struct soc_camera_device *icd = client->dev.platform_data;

	mt9m111_set_context(client, mt9m111->context);
	mt9m111_set_pixfmt(client, mt9m111->pixfmt);
	mt9m111_setup_rect(client, &mt9m111->rect);
	mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
	mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
	mt9m111_set_global_gain(client, icd->gain);
	mt9m111_set_global_gain(client, mt9m111->gain);
	mt9m111_set_autoexposure(client, mt9m111->autoexposure);
	mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
	return 0;
+24 −13
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ struct mt9t031 {
	int model;	/* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
	u16 xskip;
	u16 yskip;
	unsigned int gain;
	unsigned int exposure;
	unsigned char autoexposure;
};

@@ -301,15 +303,14 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
		ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
				rect->height + icd->y_skip_top - 1);
	if (ret >= 0 && mt9t031->autoexposure) {
		ret = set_shutter(client,
				  rect->height + icd->y_skip_top + vblank);
		unsigned int total_h = rect->height + icd->y_skip_top + vblank;
		ret = set_shutter(client, total_h);
		if (ret >= 0) {
			const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
			const struct v4l2_queryctrl *qctrl =
				soc_camera_find_qctrl(icd->ops,
						      V4L2_CID_EXPOSURE);
			icd->exposure = (shutter_max / 2 + (rect->height +
					 icd->y_skip_top + vblank - 1) *
			mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
				 (qctrl->maximum - qctrl->minimum)) /
				shutter_max + qctrl->minimum;
		}
@@ -553,6 +554,12 @@ static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
	case V4L2_CID_EXPOSURE_AUTO:
		ctrl->value = mt9t031->autoexposure;
		break;
	case V4L2_CID_GAIN:
		ctrl->value = mt9t031->gain;
		break;
	case V4L2_CID_EXPOSURE:
		ctrl->value = mt9t031->exposure;
		break;
	}
	return 0;
}
@@ -624,7 +631,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
		}

		/* Success */
		icd->gain = ctrl->value;
		mt9t031->gain = ctrl->value;
		break;
	case V4L2_CID_EXPOSURE:
		/* mt9t031 has maximum == default */
@@ -641,7 +648,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
				old, shutter);
			if (set_shutter(client, shutter) < 0)
				return -EIO;
			icd->exposure = ctrl->value;
			mt9t031->exposure = ctrl->value;
			mt9t031->autoexposure = 0;
		}
		break;
@@ -649,13 +656,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
		if (ctrl->value) {
			const u16 vblank = MT9T031_VERTICAL_BLANK;
			const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
			if (set_shutter(client, mt9t031->rect.height +
					icd->y_skip_top + vblank) < 0)
			unsigned int total_h = mt9t031->rect.height +
				icd->y_skip_top + vblank;

			if (set_shutter(client, total_h) < 0)
				return -EIO;
			qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
			icd->exposure = (shutter_max / 2 +
					 (mt9t031->rect.height +
					  icd->y_skip_top + vblank - 1) *
			mt9t031->exposure = (shutter_max / 2 + (total_h - 1) *
				 (qctrl->maximum - qctrl->minimum)) /
				shutter_max + qctrl->minimum;
			mt9t031->autoexposure = 1;
@@ -700,6 +707,10 @@ static int mt9t031_video_probe(struct i2c_client *client)
	if (ret < 0)
		dev_err(&client->dev, "Failed to initialise the camera\n");

	/* mt9t031_idle() has reset the chip to default. */
	mt9t031->exposure = 255;
	mt9t031->gain = 64;

	return ret;
}

+35 −11
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
#define MT9V022_PIXEL_OPERATION_MODE	0x0f
#define MT9V022_LED_OUT_CONTROL		0x1b
#define MT9V022_ADC_MODE_CONTROL	0x1c
#define MT9V022_ANALOG_GAIN		0x34
#define MT9V022_ANALOG_GAIN		0x35
#define MT9V022_BLACK_LEVEL_CALIB_CTRL	0x47
#define MT9V022_PIXCLK_FV_LV		0x74
#define MT9V022_DIGITAL_TEST_PATTERN	0x7f
@@ -155,6 +155,10 @@ static int mt9v022_init(struct i2c_client *client)
	if (!ret)
		/* AEC, AGC on */
		ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
	if (!ret)
		ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
	if (!ret)
		ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
	if (!ret)
		ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
	if (!ret)
@@ -540,8 +544,12 @@ static struct soc_camera_ops mt9v022_ops = {
static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct i2c_client *client = sd->priv;
	const struct v4l2_queryctrl *qctrl;
	unsigned long range;
	int data;

	qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);

	switch (ctrl->id) {
	case V4L2_CID_VFLIP:
		data = reg_read(client, MT9V022_READ_MODE);
@@ -566,6 +574,24 @@ static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
		if (data < 0)
			return -EIO;
		ctrl->value = !!(data & 0x2);
		break;
	case V4L2_CID_GAIN:
		data = reg_read(client, MT9V022_ANALOG_GAIN);
		if (data < 0)
			return -EIO;

		range = qctrl->maximum - qctrl->minimum;
		ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum;

		break;
	case V4L2_CID_EXPOSURE:
		data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
		if (data < 0)
			return -EIO;

		range = qctrl->maximum - qctrl->minimum;
		ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum;

		break;
	}
	return 0;
@@ -575,7 +601,6 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	int data;
	struct i2c_client *client = sd->priv;
	struct soc_camera_device *icd = client->dev.platform_data;
	const struct v4l2_queryctrl *qctrl;

	qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -605,12 +630,9 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
			return -EINVAL;
		else {
			unsigned long range = qctrl->maximum - qctrl->minimum;
			/* Datasheet says 16 to 64. autogain only works properly
			 * after setting gain to maximum 14. Larger values
			 * produce "white fly" noise effect. On the whole,
			 * manually setting analog gain does no good. */
			/* Valid values 16 to 64, 32 to 64 must be even. */
			unsigned long gain = ((ctrl->value - qctrl->minimum) *
					      10 + range / 2) / range + 4;
					      48 + range / 2) / range + 16;
			if (gain >= 32)
				gain &= ~1;
			/* The user wants to set gain manually, hope, she
@@ -619,11 +641,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
			if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
				return -EIO;

			dev_info(&client->dev, "Setting gain from %d to %lu\n",
			dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
				reg_read(client, MT9V022_ANALOG_GAIN), gain);
			if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
				return -EIO;
			icd->gain = ctrl->value;
		}
		break;
	case V4L2_CID_EXPOSURE:
@@ -646,7 +667,6 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
			if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
				      shutter) < 0)
				return -EIO;
			icd->exposure = ctrl->value;
		}
		break;
	case V4L2_CID_AUTOGAIN:
@@ -827,6 +847,10 @@ static int mt9v022_probe(struct i2c_client *client,
	mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;

	icd->ops		= &mt9v022_ops;
	/*
	 * MT9V022 _really_ corrupts the first read out line.
	 * TODO: verify on i.MX31
	 */
	icd->y_skip_top		= 1;

	mt9v022->rect.left	= MT9V022_COLUMN_SKIP;
+2 −1
Original line number Diff line number Diff line
@@ -548,7 +548,8 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,

	xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
	if (!xlate) {
		dev_warn(icd->dev.parent, "Format %x not found\n", pix->pixelformat);
		dev_warn(icd->dev.parent, "Format %x not found\n",
			 pix->pixelformat);
		return -EINVAL;
	}

Loading