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

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
...@@ -55,6 +55,10 @@ ...@@ -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 { ...@@ -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); ...@@ -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[] = { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment