diff options
Diffstat (limited to 'drivers/media/video/gspca/ov534.c')
-rw-r--r-- | drivers/media/video/gspca/ov534.c | 178 |
1 files changed, 110 insertions, 68 deletions
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 04753391de3..80c81dd6d68 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -34,6 +34,8 @@ #include "gspca.h" +#include <linux/fixp-arith.h> + #define OV534_REG_ADDRESS 0xf1 /* sensor address */ #define OV534_REG_SUBADDR 0xf2 #define OV534_REG_WRITE 0xf3 @@ -53,6 +55,8 @@ MODULE_LICENSE("GPL"); /* controls */ enum e_ctrl { + HUE, + SATURATION, BRIGHTNESS, CONTRAST, GAIN, @@ -63,7 +67,6 @@ enum e_ctrl { SHARPNESS, HFLIP, VFLIP, - COLORS, LIGHTFREQ, NCTRLS /* number of controls */ }; @@ -87,22 +90,47 @@ enum sensors { }; /* V4L2 controls supported by the driver */ +static void sethue(struct gspca_dev *gspca_dev); +static void setsaturation(struct gspca_dev *gspca_dev); static void setbrightness(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev); static void setgain(struct gspca_dev *gspca_dev); static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val); +static void setagc(struct gspca_dev *gspca_dev); static void setawb(struct gspca_dev *gspca_dev); static void setaec(struct gspca_dev *gspca_dev); static void setsharpness(struct gspca_dev *gspca_dev); static void sethvflip(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); static void setlightfreq(struct gspca_dev *gspca_dev); static int sd_start(struct gspca_dev *gspca_dev); static void sd_stopN(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[] = { +[HUE] = { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -90, + .maximum = 90, + .step = 1, + .default_value = 0, + }, + .set_control = sethue + }, +[SATURATION] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + }, + .set_control = setsaturation + }, [BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, @@ -161,7 +189,7 @@ static const struct ctrl sd_ctrls[] = { .step = 1, .default_value = 1, }, - .set = sd_setagc + .set_control = setagc }, [AWB] = { { @@ -223,18 +251,6 @@ static const struct ctrl sd_ctrls[] = { }, .set_control = sethvflip }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 6, - .step = 1, - .default_value = 3, - }, - .set_control = setcolors - }, [LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -684,7 +700,7 @@ static const u8 sensor_init_772x[][2] = { { 0x9c, 0x20 }, { 0x9e, 0x81 }, - { 0xa6, 0x04 }, + { 0xa6, 0x07 }, { 0x7e, 0x0c }, { 0x7f, 0x16 }, { 0x80, 0x2a }, @@ -835,6 +851,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) int i; for (i = 0; i < 5; i++) { + msleep(10); data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); switch (data) { @@ -955,6 +972,74 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "frame_rate: %d", r->fps); } +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[HUE].val; + if (sd->sensor == SENSOR_OV767x) { + /* TBD */ + } else { + s16 huesin; + s16 huecos; + + /* fixp_sin and fixp_cos accept only positive values, while + * our val is between -90 and 90 + */ + val += 360; + + /* According to the datasheet the registers expect HUESIN and + * HUECOS to be the result of the trigonometric functions, + * scaled by 0x80. + * + * The 0x100 here represents the maximun absolute value + * returned byt fixp_sin and fixp_cos, so the scaling will + * consider the result like in the interval [-1.0, 1.0]. + */ + huesin = fixp_sin(val) * 0x80 / 0x100; + huecos = fixp_cos(val) * 0x80 / 0x100; + + if (huesin < 0) { + sccb_reg_write(gspca_dev, 0xab, + sccb_reg_read(gspca_dev, 0xab) | 0x2); + huesin = -huesin; + } else { + sccb_reg_write(gspca_dev, 0xab, + sccb_reg_read(gspca_dev, 0xab) & ~0x2); + + } + sccb_reg_write(gspca_dev, 0xa9, (u8)huecos); + sccb_reg_write(gspca_dev, 0xaa, (u8)huesin); + } +} + +static void setsaturation(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[SATURATION].val; + if (sd->sensor == SENSOR_OV767x) { + int i; + static u8 color_tb[][6] = { + {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, + {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, + {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, + {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, + {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, + {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, + {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, + }; + + for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) + sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); + } else { + sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */ + sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */ + } +} + static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1132,26 +1217,6 @@ static void sethvflip(struct gspca_dev *gspca_dev) } } -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - int i; - static u8 color_tb[][6] = { - {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, - {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, - {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, - {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, - {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, - {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, - {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, - }; - - val = sd->ctrls[COLORS].val; - for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) - sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); -} - static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1178,10 +1243,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->ctrls = sd->ctrls; - /* the auto white balance control works only when auto gain is set */ - if (sd_ctrls[AGC].qctrl.default_value == 0) - gspca_dev->ctrl_inac |= (1 << AWB); - cam->cam_mode = ov772x_mode; cam->nmodes = ARRAY_SIZE(ov772x_mode); @@ -1225,9 +1286,13 @@ static int sd_init(struct gspca_dev *gspca_dev) if ((sensor_id & 0xfff0) == 0x7670) { sd->sensor = SENSOR_OV767x; - gspca_dev->ctrl_dis = (1 << GAIN) | + gspca_dev->ctrl_dis = (1 << HUE) | + (1 << GAIN) | (1 << AGC) | (1 << SHARPNESS); /* auto */ + sd->ctrls[SATURATION].min = 0, + sd->ctrls[SATURATION].max = 6, + sd->ctrls[SATURATION].def = 3, sd->ctrls[BRIGHTNESS].min = -127; sd->ctrls[BRIGHTNESS].max = 127; sd->ctrls[BRIGHTNESS].def = 0; @@ -1243,7 +1308,6 @@ static int sd_init(struct gspca_dev *gspca_dev) gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); } else { sd->sensor = SENSOR_OV772x; - gspca_dev->ctrl_dis = (1 << COLORS); gspca_dev->cam.bulk = 1; gspca_dev->cam.bulk_size = 16384; gspca_dev->cam.bulk_nurbs = 2; @@ -1302,6 +1366,9 @@ static int sd_start(struct gspca_dev *gspca_dev) set_frame_rate(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << HUE))) + sethue(gspca_dev); + setsaturation(gspca_dev); if (!(gspca_dev->ctrl_dis & (1 << AGC))) setagc(gspca_dev); setawb(gspca_dev); @@ -1314,8 +1381,6 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) setsharpness(gspca_dev); sethvflip(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << COLORS))) - setcolors(gspca_dev); setlightfreq(gspca_dev); ov534_set_led(gspca_dev, 1); @@ -1418,29 +1483,6 @@ scan_next: } while (remaining_len > 0); } -static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AGC].val = val; - - /* the auto white balance control works only - * when auto gain is set */ - if (val) { - gspca_dev->ctrl_inac &= ~(1 << AWB); - } else { - gspca_dev->ctrl_inac |= (1 << AWB); - if (sd->ctrls[AWB].val) { - sd->ctrls[AWB].val = 0; - if (gspca_dev->streaming) - setawb(gspca_dev); - } - } - if (gspca_dev->streaming) - setagc(gspca_dev); - return gspca_dev->usb_err; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { |