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: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
f14a2972e4
commit
065b6f7a34
1 changed files with 51 additions and 6 deletions
|
@ -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"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue