Esempio n. 1
0
static int mt9v011_remove(struct i2c_client *c)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(c);
	struct mt9v011 *core = to_mt9v011(sd);

	v4l2_dbg(1, debug, sd,
		"mt9v011.c: removing mt9v011 adapter on address 0x%x\n",
		c->addr << 1);

	v4l2_device_unregister_subdev(sd);
	v4l2_ctrl_handler_free(&core->ctrls);
	kfree(to_mt9v011(sd));
	return 0;
}
Esempio n. 2
0
static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct mt9v011 *core = to_mt9v011(sd);

	v4l2_dbg(1, debug, sd, "g_ctrl called\n");

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		ctrl->value = core->global_gain;
		return 0;
	case V4L2_CID_EXPOSURE:
		ctrl->value = core->exposure;
		return 0;
	case V4L2_CID_RED_BALANCE:
		ctrl->value = core->red_bal;
		return 0;
	case V4L2_CID_BLUE_BALANCE:
		ctrl->value = core->blue_bal;
		return 0;
	case V4L2_CID_HFLIP:
		ctrl->value = core->hflip ? 1 : 0;
		return 0;
	case V4L2_CID_VFLIP:
		ctrl->value = core->vflip ? 1 : 0;
		return 0;
	}
	return -EINVAL;
}
Esempio n. 3
0
static void set_res(struct v4l2_subdev *sd)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned vstart, hstart;

	/*
	 * The mt9v011 doesn't have scaling. So, in order to select the desired
	 * resolution, we're cropping at the middle of the sensor.
	 * hblank and vblank should be adjusted, in order to warrant that
	 * we'll preserve the line timings for 30 fps, no matter what resolution
	 * is selected.
	 * NOTE: datasheet says that width (and height) should be filled with
	 * width-1. However, this doesn't work, since one pixel per line will
	 * be missing.
	 */

	hstart = 20 + (640 - core->width) / 2;
	mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
	mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
	mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);

	vstart = 8 + (480 - core->height) / 2;
	mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
	mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
	mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);

	calc_fps(sd, NULL, NULL);
};
Esempio n. 4
0
static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned height, width, hblank, vblank, speed;
	unsigned row_time, t_time;
	u64 frames_per_ms;
	unsigned tmp;

	height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
	width = mt9v011_read(sd, R04_MT9V011_WIDTH);
	hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
	vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);
	speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED);

	row_time = (width + 113 + hblank) * (speed + 2);
	t_time = row_time * (height + vblank + 1);

	frames_per_ms = core->xtal * 1000l;
	do_div(frames_per_ms, t_time);
	tmp = frames_per_ms;

	v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n",
		tmp / 1000, tmp % 1000, t_time);

	if (numerator && denominator) {
		*numerator = 1000;
		*denominator = (u32)frames_per_ms;
	}
}
Esempio n. 5
0
static void set_balance(struct v4l2_subdev *sd)
{
	struct mt9v011 *core = to_mt9v011(sd);
	u16 green_gain, blue_gain, red_gain;
	u16 exposure;
	s16 bal;

	exposure = core->exposure;

	green_gain = calc_mt9v011_gain(core->global_gain);

	bal = core->global_gain;
	bal += (core->blue_bal * core->global_gain / (1 << 7));
	blue_gain = calc_mt9v011_gain(bal);

	bal = core->global_gain;
	bal += (core->red_bal * core->global_gain / (1 << 7));
	red_gain = calc_mt9v011_gain(bal);

	mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
	mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
	mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
	mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
	mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
}
Esempio n. 6
0
static void set_read_mode(struct v4l2_subdev *sd)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned mode = 0x1000;

	if (core->hflip)
		mode |= 0x4000;

	if (core->vflip)
		mode |= 0x8000;

	mt9v011_write(sd, R20_MT9V011_READ_MODE, mode);
}
Esempio n. 7
0
static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned *xtal = data;

	v4l2_dbg(1, debug, sd, "s_config called\n");

	if (xtal) {
		core->xtal = *xtal;
		v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
			 *xtal / 1000000, (*xtal / 1000) % 1000);
	}

	return 0;
}
Esempio n. 8
0
static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
	struct mt9v011 *core = to_mt9v011(sd);
	int rc;

	rc = mt9v011_try_mbus_fmt(sd, fmt);
	if (rc < 0)
		return -EINVAL;

	core->width = fmt->width;
	core->height = fmt->height;

	set_res(sd);

	return 0;
}
Esempio n. 9
0
static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct mt9v011 *core = to_mt9v011(sd);
	u8 i, n;
	n = ARRAY_SIZE(mt9v011_qctrl);

	for (i = 0; i < n; i++) {
		if (ctrl->id != mt9v011_qctrl[i].id)
			continue;
		if (ctrl->value < mt9v011_qctrl[i].minimum ||
		    ctrl->value > mt9v011_qctrl[i].maximum)
			return -ERANGE;
		v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
					ctrl->id, ctrl->value);
		break;
	}

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		core->global_gain = ctrl->value;
		break;
	case V4L2_CID_EXPOSURE:
		core->exposure = ctrl->value;
		break;
	case V4L2_CID_RED_BALANCE:
		core->red_bal = ctrl->value;
		break;
	case V4L2_CID_BLUE_BALANCE:
		core->blue_bal = ctrl->value;
		break;
	case V4L2_CID_HFLIP:
		core->hflip = ctrl->value;
		set_read_mode(sd);
		return 0;
	case V4L2_CID_VFLIP:
		core->vflip = ctrl->value;
		set_read_mode(sd);
		return 0;
	default:
		return -EINVAL;
	}

	set_balance(sd);

	return 0;
}
Esempio n. 10
0
static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
	struct v4l2_pix_format *pix = &fmt->fmt.pix;
	struct mt9v011 *core = to_mt9v011(sd);
	int rc;

	rc = mt9v011_try_fmt(sd, fmt);
	if (rc < 0)
		return -EINVAL;

	core->width = pix->width;
	core->height = pix->height;

	set_res(sd);

	return 0;
}
static void set_res(struct v4l2_subdev *sd)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned vstart, hstart;


	hstart = 20 + (640 - core->width) / 2;
	mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
	mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
	mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);

	vstart = 8 + (480 - core->height) / 2;
	mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
	mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
	mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);

	calc_fps(sd, NULL, NULL);
};
Esempio n. 12
0
static void set_balance(struct v4l2_subdev *sd)
{
	struct mt9v011 *core = to_mt9v011(sd);
	u16 green1_gain, green2_gain, blue_gain, red_gain;

	green1_gain = core->global_gain;
	green2_gain = core->global_gain;

	blue_gain = core->global_gain +
		    core->global_gain * core->blue_bal / (1 << 9);

	red_gain = core->global_gain +
		   core->global_gain * core->blue_bal / (1 << 9);

	mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain);
	mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
	mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
	mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
}
Esempio n. 13
0
static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned height, width, hblank, vblank;
	unsigned row_time, line_time;
	u64 t_time, speed;

	/* Avoid bogus calculus */
	if (!numerator || !denominator)
		return 0;

	height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
	width = mt9v011_read(sd, R04_MT9V011_WIDTH);
	hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
	vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);

	row_time = width + 113 + hblank;
	line_time = height + vblank + 1;

	t_time = core->xtal * ((u64)numerator);
	/* round to the closest value */
	t_time += denominator / 2;
	do_div(t_time, denominator);

	speed = t_time;
	do_div(speed, row_time * line_time);

	/* Avoid having a negative value for speed */
	if (speed < 2)
		speed = 0;
	else
		speed -= 2;

	/* Avoid speed overflow */
	if (speed > 15)
		return 15;

	return (u16)speed;
}
static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator)
{
	struct mt9v011 *core = to_mt9v011(sd);
	unsigned height, width, hblank, vblank;
	unsigned row_time, line_time;
	u64 t_time, speed;

	
	if (!numerator || !denominator)
		return 0;

	height = mt9v011_read(sd, R03_MT9V011_HEIGHT);
	width = mt9v011_read(sd, R04_MT9V011_WIDTH);
	hblank = mt9v011_read(sd, R05_MT9V011_HBLANK);
	vblank = mt9v011_read(sd, R06_MT9V011_VBLANK);

	row_time = width + 113 + hblank;
	line_time = height + vblank + 1;

	t_time = core->xtal * ((u64)numerator);
	
	t_time += denominator / 2;
	do_div(t_time, denominator);

	speed = t_time;
	do_div(speed, row_time * line_time);

	
	if (speed < 2)
		speed = 0;
	else
		speed -= 2;

	
	if (speed > 15)
		return 15;

	return (u16)speed;
}