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

Commit 065b6f7a authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (13242): gspca_mr97310a: Add minimum clock divider control



When "shooting" certain (quite rare) scenes, the mr97310's compression is not
effective and it cannot keep up with the data stream. This patch adds a
minimum clock divider control, which influences the maximum framerate,
libv4l will automatically increase this minimum clockdiv control when it
detect the cam cannot keep up.

Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent f14a2972
Loading
Loading
Loading
Loading
+51 −6
Original line number Original line Diff line number Diff line
@@ -55,6 +55,10 @@
#define MR97310A_GAIN_MAX		31
#define MR97310A_GAIN_MAX		31
#define MR97310A_GAIN_DEFAULT		25
#define MR97310A_GAIN_DEFAULT		25


#define MR97310A_MIN_CLOCKDIV_MIN	3
#define MR97310A_MIN_CLOCKDIV_MAX	8
#define MR97310A_MIN_CLOCKDIV_DEFAULT	3

MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,"
	      "Theodore Kilgore <kilgota@auburn.edu>");
	      "Theodore Kilgore <kilgota@auburn.edu>");
MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
@@ -76,6 +80,7 @@ struct sd {
	int brightness;
	int brightness;
	u16 exposure;
	u16 exposure;
	u8 gain;
	u8 gain;
	u8 min_clockdiv;
};
};


struct sensor_w_data {
struct sensor_w_data {
@@ -92,6 +97,8 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val);
static void setbrightness(struct gspca_dev *gspca_dev);
static void setbrightness(struct gspca_dev *gspca_dev);
static void setexposure(struct gspca_dev *gspca_dev);
static void setexposure(struct gspca_dev *gspca_dev);
static void setgain(struct gspca_dev *gspca_dev);
static void setgain(struct gspca_dev *gspca_dev);
@@ -160,6 +167,21 @@ static struct ctrl sd_ctrls[] = {
		.set = sd_setgain,
		.set = sd_setgain,
		.get = sd_getgain,
		.get = sd_getgain,
	},
	},
	{
#define MIN_CLOCKDIV_IDX 4
		{
			.id = V4L2_CID_PRIVATE_BASE,
			.type = V4L2_CTRL_TYPE_INTEGER,
			.name = "Minimum Clock Divider",
			.minimum = MR97310A_MIN_CLOCKDIV_MIN,
			.maximum = MR97310A_MIN_CLOCKDIV_MAX,
			.step = 1,
			.default_value = MR97310A_MIN_CLOCKDIV_DEFAULT,
			.flags = 0,
		},
		.set = sd_setmin_clockdiv,
		.get = sd_getmin_clockdiv,
	},
};
};


static const struct v4l2_pix_format vga_mode[] = {
static const struct v4l2_pix_format vga_mode[] = {
@@ -544,14 +566,16 @@ static int sd_config(struct gspca_dev *gspca_dev,
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
					      (1 << ARGUS_QC_BRIGHTNESS_IDX);
					      (1 << ARGUS_QC_BRIGHTNESS_IDX);
		else
		else
			gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX);
			gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
					      (1 << MIN_CLOCKDIV_IDX);
	} else {
	} else {
		/* All controls need to be disabled if VGA sensor_type is 0 */
		/* All controls need to be disabled if VGA sensor_type is 0 */
		if (sd->sensor_type == 0)
		if (sd->sensor_type == 0)
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
					      (1 << ARGUS_QC_BRIGHTNESS_IDX) |
					      (1 << ARGUS_QC_BRIGHTNESS_IDX) |
					      (1 << EXPOSURE_IDX) |
					      (1 << EXPOSURE_IDX) |
					      (1 << GAIN_IDX);
					      (1 << GAIN_IDX) |
					      (1 << MIN_CLOCKDIV_IDX);
		else if (sd->do_lcd_stop)
		else if (sd->do_lcd_stop)
			/* Argus QuickClix has different brightness limits */
			/* Argus QuickClix has different brightness limits */
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX);
			gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX);
@@ -562,6 +586,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
	sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
	sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
	sd->exposure = MR97310A_EXPOSURE_DEFAULT;
	sd->exposure = MR97310A_EXPOSURE_DEFAULT;
	sd->gain = MR97310A_GAIN_DEFAULT;
	sd->gain = MR97310A_GAIN_DEFAULT;
	sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT;


	return 0;
	return 0;
}
}
@@ -837,6 +862,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
{
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct sd *sd = (struct sd *) gspca_dev;
	int exposure;
	int exposure;
	u8 buf[2];


	if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
	if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
		return;
		return;
@@ -858,8 +884,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
		u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
		u8 clockdiv = (60 * sd->exposure + 7999) / 8000;


		/* Limit framerate to not exceed usb bandwidth */
		/* Limit framerate to not exceed usb bandwidth */
		if (clockdiv < 3 && gspca_dev->width >= 320)
		if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320)
			clockdiv = 3;
			clockdiv = sd->min_clockdiv;
		else if (clockdiv < 2)
		else if (clockdiv < 2)
			clockdiv = 2;
			clockdiv = 2;


@@ -875,9 +901,10 @@ static void setexposure(struct gspca_dev *gspca_dev)
		/* exposure register value is reversed! */
		/* exposure register value is reversed! */
		exposure = 511 - exposure;
		exposure = 511 - exposure;


		buf[0] = exposure & 0xff;
		buf[1] = exposure >> 8;
		sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2);
		sensor_write1(gspca_dev, 0x02, clockdiv);
		sensor_write1(gspca_dev, 0x02, clockdiv);
		sensor_write1(gspca_dev, 0x0e, exposure & 0xff);
		sensor_write1(gspca_dev, 0x0f, exposure >> 8);
	}
	}
}
}


@@ -949,6 +976,24 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
	return 0;
	return 0;
}
}


static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	sd->min_clockdiv = val;
	if (gspca_dev->streaming)
		setexposure(gspca_dev);
	return 0;
}

static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->min_clockdiv;
	return 0;
}

/* Include pac common sof detection functions */
/* Include pac common sof detection functions */
#include "pac_common.h"
#include "pac_common.h"