Commit 02ab18b0 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

V4L/DVB (12072): gspca-ov519: add extra controls

This patch adds autobrightness (so that it can
be turned off to make the already present brightness
control work) and light frequency filtering controls.

The lightfreq control needed 2 different entries
in the ctrls array, as the number of options differs
depending on the sensor. Always one of the 2 entires is
disabled ofcourse.
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b8bfb5fb
...@@ -65,6 +65,8 @@ struct sd { ...@@ -65,6 +65,8 @@ struct sd {
__u8 colors; __u8 colors;
__u8 hflip; __u8 hflip;
__u8 vflip; __u8 vflip;
__u8 autobrightness;
__u8 freq;
__u8 stopped; /* Streaming is temporarily paused */ __u8 stopped; /* Streaming is temporarily paused */
...@@ -94,11 +96,17 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); ...@@ -94,11 +96,17 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(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 setcontrast(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev);
static void setcolors(struct gspca_dev *gspca_dev); static void setcolors(struct gspca_dev *gspca_dev);
static void setautobrightness(struct sd *sd);
static void setfreq(struct sd *sd);
static struct ctrl sd_ctrls[] = { static const struct ctrl sd_ctrls[] = {
{ {
{ {
.id = V4L2_CID_BRIGHTNESS, .id = V4L2_CID_BRIGHTNESS,
...@@ -141,7 +149,7 @@ static struct ctrl sd_ctrls[] = { ...@@ -141,7 +149,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors, .set = sd_setcolors,
.get = sd_getcolors, .get = sd_getcolors,
}, },
/* next controls work with ov7670 only */ /* The flip controls work with ov7670 only */
#define HFLIP_IDX 3 #define HFLIP_IDX 3
{ {
{ {
...@@ -172,6 +180,51 @@ static struct ctrl sd_ctrls[] = { ...@@ -172,6 +180,51 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setvflip, .set = sd_setvflip,
.get = sd_getvflip, .get = sd_getvflip,
}, },
#define AUTOBRIGHT_IDX 5
{
{
.id = V4L2_CID_AUTOBRIGHTNESS,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Auto Brightness",
.minimum = 0,
.maximum = 1,
.step = 1,
#define AUTOBRIGHT_DEF 1
.default_value = AUTOBRIGHT_DEF,
},
.set = sd_setautobrightness,
.get = sd_getautobrightness,
},
#define FREQ_IDX 6
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
#define FREQ_DEF 0
.default_value = FREQ_DEF,
},
.set = sd_setfreq,
.get = sd_getfreq,
},
#define OV7670_FREQ_IDX 7
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 0,
.maximum = 3, /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */
.step = 1,
#define OV7670_FREQ_DEF 3
.default_value = OV7670_FREQ_DEF,
},
.set = sd_setfreq,
.get = sd_getfreq,
},
}; };
static const struct v4l2_pix_format ov519_vga_mode[] = { static const struct v4l2_pix_format ov519_vga_mode[] = {
...@@ -416,7 +469,7 @@ static const struct ov_i2c_regvals norm_6x30[] = { ...@@ -416,7 +469,7 @@ static const struct ov_i2c_regvals norm_6x30[] = {
{ 0x07, 0x2d }, /* Sharpness */ { 0x07, 0x2d }, /* Sharpness */
{ 0x0c, 0x20 }, { 0x0c, 0x20 },
{ 0x0d, 0x20 }, { 0x0d, 0x20 },
{ 0x0e, 0x20 }, { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */
{ 0x0f, 0x05 }, { 0x0f, 0x05 },
{ 0x10, 0x9a }, { 0x10, 0x9a },
{ 0x11, 0x00 }, /* Pixel clock = fastest */ { 0x11, 0x00 }, /* Pixel clock = fastest */
...@@ -1659,9 +1712,21 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -1659,9 +1712,21 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->colors = COLOR_DEF; sd->colors = COLOR_DEF;
sd->hflip = HFLIP_DEF; sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF; sd->vflip = VFLIP_DEF;
if (sd->sensor != SEN_OV7670) sd->autobrightness = AUTOBRIGHT_DEF;
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) if (sd->sensor == SEN_OV7670) {
| (1 << VFLIP_IDX); sd->freq = OV7670_FREQ_DEF;
gspca_dev->ctrl_dis = 1 << FREQ_IDX;
} else {
sd->freq = FREQ_DEF;
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
(1 << OV7670_FREQ_IDX);
}
if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
/* OV8610 Frequency filter control should work but needs testing */
if (sd->sensor == SEN_OV8610)
gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
return 0; return 0;
error: error:
PDEBUG(D_ERR, "OV519 Config failed"); PDEBUG(D_ERR, "OV519 Config failed");
...@@ -2233,7 +2298,6 @@ static int set_ov_sensor_window(struct sd *sd) ...@@ -2233,7 +2298,6 @@ static int set_ov_sensor_window(struct sd *sd)
msleep(10); /* need to sleep between read and write to msleep(10); /* need to sleep between read and write to
* same reg! */ * same reg! */
i2c_w(sd, OV7670_REG_VREF, v); i2c_w(sd, OV7670_REG_VREF, v);
sethvflip(sd);
} else { } else {
i2c_w(sd, 0x17, hwsbase); i2c_w(sd, 0x17, hwsbase);
i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale)); i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale));
...@@ -2268,6 +2332,9 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -2268,6 +2332,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
setcontrast(gspca_dev); setcontrast(gspca_dev);
setbrightness(gspca_dev); setbrightness(gspca_dev);
setcolors(gspca_dev); setcolors(gspca_dev);
sethvflip(sd);
setautobrightness(sd);
setfreq(sd);
ret = ov51x_restart(sd); ret = ov51x_restart(sd);
if (ret < 0) if (ret < 0)
...@@ -2394,8 +2461,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) ...@@ -2394,8 +2461,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
break; break;
case SEN_OV7620: case SEN_OV7620:
/* 7620 doesn't like manual changes when in auto mode */ /* 7620 doesn't like manual changes when in auto mode */
/*fixme if (!sd->autobrightness)
* if (!sd->auto_brt) */
i2c_w(sd, OV7610_REG_BRT, val); i2c_w(sd, OV7610_REG_BRT, val);
break; break;
case SEN_OV7670: case SEN_OV7670:
...@@ -2482,6 +2548,70 @@ static void setcolors(struct gspca_dev *gspca_dev) ...@@ -2482,6 +2548,70 @@ static void setcolors(struct gspca_dev *gspca_dev)
} }
} }
static void setautobrightness(struct sd *sd)
{
if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670)
return;
i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
}
static void setfreq(struct sd *sd)
{
if (sd->sensor == SEN_OV7670) {
switch (sd->freq) {
case 0: /* Banding filter disabled */
i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
break;
case 1: /* 50 hz */
i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18);
break;
case 2: /* 60 hz */
i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18);
break;
case 3: /* Auto hz */
i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO,
0x18);
break;
}
} else {
switch (sd->freq) {
case 0: /* Banding filter disabled */
i2c_w_mask(sd, 0x2d, 0x00, 0x04);
i2c_w_mask(sd, 0x2a, 0x00, 0x80);
break;
case 1: /* 50 hz (filter on and framerate adj) */
i2c_w_mask(sd, 0x2d, 0x04, 0x04);
i2c_w_mask(sd, 0x2a, 0x80, 0x80);
/* 20 fps -> 16.667 fps */
if (sd->sensor == SEN_OV6620 ||
sd->sensor == SEN_OV6630)
i2c_w(sd, 0x2b, 0x5e);
else
i2c_w(sd, 0x2b, 0xac);
break;
case 2: /* 60 hz (filter on, ...) */
i2c_w_mask(sd, 0x2d, 0x04, 0x04);
if (sd->sensor == SEN_OV6620 ||
sd->sensor == SEN_OV6630) {
/* 20 fps -> 15 fps */
i2c_w_mask(sd, 0x2a, 0x80, 0x80);
i2c_w(sd, 0x2b, 0xa8);
} else {
/* no framerate adj. */
i2c_w_mask(sd, 0x2a, 0x00, 0x80);
}
break;
}
}
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -2572,6 +2702,71 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) ...@@ -2572,6 +2702,71 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
return 0; return 0;
} }
static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->autobrightness = val;
if (gspca_dev->streaming)
setautobrightness(sd);
return 0;
}
static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->autobrightness;
return 0;
}
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->freq = val;
if (gspca_dev->streaming)
setfreq(sd);
return 0;
}
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->freq;
return 0;
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
struct sd *sd = (struct sd *) gspca_dev;
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
switch (menu->index) {
case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
strcpy((char *) menu->name, "NoFliker");
return 0;
case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
strcpy((char *) menu->name, "50 Hz");
return 0;
case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
strcpy((char *) menu->name, "60 Hz");
return 0;
case 3:
if (sd->sensor != SEN_OV7670)
return -EINVAL;
strcpy((char *) menu->name, "Automatic");
return 0;
}
break;
}
return -EINVAL;
}
/* sub-driver description */ /* sub-driver description */
static const struct sd_desc sd_desc = { static const struct sd_desc sd_desc = {
.name = MODULE_NAME, .name = MODULE_NAME,
...@@ -2582,6 +2777,7 @@ static const struct sd_desc sd_desc = { ...@@ -2582,6 +2777,7 @@ static const struct sd_desc sd_desc = {
.start = sd_start, .start = sd_start,
.stopN = sd_stopN, .stopN = sd_stopN,
.pkt_scan = sd_pkt_scan, .pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
}; };
/* -- module initialisation -- */ /* -- module initialisation -- */
......
...@@ -894,9 +894,10 @@ enum v4l2_colorfx { ...@@ -894,9 +894,10 @@ enum v4l2_colorfx {
V4L2_COLORFX_BW = 1, V4L2_COLORFX_BW = 1,
V4L2_COLORFX_SEPIA = 2, V4L2_COLORFX_SEPIA = 2,
}; };
#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32)
/* last CID + 1 */ /* last CID + 1 */
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+32) #define V4L2_CID_LASTP1 (V4L2_CID_BASE+33)
/* MPEG-class control IDs defined by V4L2 */ /* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
......
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