summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/zc3xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/zc3xx.c')
-rw-r--r--drivers/media/video/gspca/zc3xx.c128
1 files changed, 97 insertions, 31 deletions
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 47236a58bf3..fa164e861cd 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -1,7 +1,7 @@
/*
* Z-Star/Vimicro zc301/zc302p/vc30x library
*
- * Copyright (C) 2009-2010 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
*
* This program is free software; you can redistribute it and/or modify
@@ -39,6 +39,7 @@ static int force_sensor = -1;
enum e_ctrl {
BRIGHTNESS,
CONTRAST,
+ EXPOSURE,
GAMMA,
AUTOGAIN,
LIGHTFREQ,
@@ -46,6 +47,8 @@ enum e_ctrl {
NCTRLS /* number of controls */
};
+#define AUTOGAIN_DEF 1
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
@@ -73,7 +76,7 @@ enum sensors {
SENSOR_CS2102K,
SENSOR_GC0303,
SENSOR_GC0305,
- SENSOR_HDCS2020b,
+ SENSOR_HDCS2020,
SENSOR_HV7131B,
SENSOR_HV7131R,
SENSOR_ICM105A,
@@ -92,7 +95,8 @@ enum sensors {
/* V4L2 controls supported by the driver */
static void setcontrast(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static void setlightfreq(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
@@ -121,6 +125,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setcontrast
},
+[EXPOSURE] = {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0x30d,
+ .maximum = 0x493e,
+ .step = 1,
+ .default_value = 0x927
+ },
+ .set_control = setexposure
+ },
[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
@@ -141,9 +157,10 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+ .default_value = AUTOGAIN_DEF,
+ .flags = V4L2_CTRL_FLAG_UPDATE
},
- .set_control = setautogain
+ .set = sd_setautogain
},
[LIGHTFREQ] = {
{
@@ -1498,7 +1515,7 @@ static const struct usb_action gc0305_NoFliker[] = {
{}
};
-static const struct usb_action hdcs2020b_InitialScale[] = {
+static const struct usb_action hdcs2020_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */
@@ -1630,7 +1647,7 @@ static const struct usb_action hdcs2020b_InitialScale[] = {
{0xa0, 0x40, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action hdcs2020b_Initial[] = {
+static const struct usb_action hdcs2020_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -1758,7 +1775,7 @@ static const struct usb_action hdcs2020b_Initial[] = {
{0xa0, 0x40, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action hdcs2020b_50HZ[] = {
+static const struct usb_action hdcs2020_50HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x13, 0x0018}, /* 00,13,18,aa */
{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
@@ -1779,7 +1796,7 @@ static const struct usb_action hdcs2020b_50HZ[] = {
{0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */
{}
};
-static const struct usb_action hdcs2020b_60HZ[] = {
+static const struct usb_action hdcs2020_60HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x13, 0x0031}, /* 00,13,31,aa */
{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
@@ -1800,7 +1817,7 @@ static const struct usb_action hdcs2020b_60HZ[] = {
{0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */
{}
};
-static const struct usb_action hdcs2020b_NoFliker[] = {
+static const struct usb_action hdcs2020_NoFliker[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0x13, 0x0010}, /* 00,13,10,aa */
{0xaa, 0x14, 0x0001}, /* 00,14,01,aa */
@@ -2126,7 +2143,6 @@ static const struct usb_action hv7131r_Initial[] = {
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-
{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
@@ -2878,7 +2894,7 @@ static const struct usb_action mc501cb_Initial[] = {
{0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
{0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
{0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
- {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+ {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
{0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
{0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
{0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
@@ -2998,7 +3014,7 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
{0xaa, 0x11, 0x0001}, /* 00,11,01,aa */
{0xaa, 0x30, 0x0000}, /* 00,30,00,aa */
{0xaa, 0x60, 0x0000}, /* 00,60,00,aa */
- {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */
+ {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */
{0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */
{0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */
{0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */
@@ -3310,7 +3326,7 @@ static const struct usb_action ov7620_50HZ[] = {
{0xaa, 0x10, 0x0082}, /* 00,10,82,aa */
{0xaa, 0x76, 0x0003}, /* 00,76,03,aa */
/* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc
- if mode0 (640x480) */
+ * if mode0 (640x480) */
{}
};
static const struct usb_action ov7620_60HZ[] = {
@@ -5828,7 +5844,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
[SENSOR_CS2102K] = NULL,
[SENSOR_GC0303] = gc0303_matrix,
[SENSOR_GC0305] = gc0305_matrix,
- [SENSOR_HDCS2020b] = NULL,
+ [SENSOR_HDCS2020] = NULL,
[SENSOR_HV7131B] = NULL,
[SENSOR_HV7131R] = po2030_matrix,
[SENSOR_ICM105A] = po2030_matrix,
@@ -5927,6 +5943,26 @@ static void setcontrast(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */
}
+static void getexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
+ | (i2c_read(gspca_dev, 0x26) << 1)
+ | (i2c_read(gspca_dev, 0x27) >> 7);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+
+ val = sd->ctrls[EXPOSURE].val;
+ i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
+ i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
+ i2c_write(gspca_dev, 0x27, val << 7, 0x00);
+}
+
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -5990,10 +6026,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
{gc0305_NoFliker, gc0305_NoFliker,
gc0305_50HZ, gc0305_50HZ,
gc0305_60HZ, gc0305_60HZ},
- [SENSOR_HDCS2020b] =
- {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
- hdcs2020b_50HZ, hdcs2020b_50HZ,
- hdcs2020b_60HZ, hdcs2020b_60HZ},
+ [SENSOR_HDCS2020] =
+ {hdcs2020_NoFliker, hdcs2020_NoFliker,
+ hdcs2020_50HZ, hdcs2020_50HZ,
+ hdcs2020_60HZ, hdcs2020_60HZ},
[SENSOR_HV7131B] =
{hv7131b_NoFliker, hv7131b_NoFlikerScale,
hv7131b_50HZ, hv7131b_50HZScale,
@@ -6091,7 +6127,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
{
- reg_w(gspca_dev, 0x01, 0x0000); /* led off */
+ reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */
switch (sensor) {
case SENSOR_PAS106:
reg_w(gspca_dev, 0x03, 0x003a);
@@ -6310,6 +6346,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
return 0x0a; /* PB0330 */
}
+ /* probe gc0303 / gc0305 */
reg_w(gspca_dev, 0x01, 0x0000);
reg_w(gspca_dev, 0x01, 0x0001);
reg_w(gspca_dev, 0x98, 0x008b);
@@ -6414,6 +6451,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
+ /* if USB 1.1, let some bandwidth for the audio device */
+ if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
+ gspca_dev->nbalt--;
+
return 0;
}
@@ -6429,7 +6470,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_CS2102K] = 5,
[SENSOR_GC0303] = 3,
[SENSOR_GC0305] = 4,
- [SENSOR_HDCS2020b] = 4,
+ [SENSOR_HDCS2020] = 4,
[SENSOR_HV7131B] = 4,
[SENSOR_HV7131R] = 4,
[SENSOR_ICM105A] = 4,
@@ -6450,7 +6491,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_CS2102K] = 1,
[SENSOR_GC0303] = 1,
[SENSOR_GC0305] = 1,
- [SENSOR_HDCS2020b] = 1,
+ [SENSOR_HDCS2020] = 1,
[SENSOR_HV7131B] = 1,
[SENSOR_HV7131R] = 1,
[SENSOR_ICM105A] = 1,
@@ -6513,8 +6554,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
sd->sensor = SENSOR_CS2102;
break;
case 0x08:
- PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)");
- sd->sensor = SENSOR_HDCS2020b;
+ PDEBUG(D_PROBE, "Find Sensor HDCS2020");
+ sd->sensor = SENSOR_HDCS2020;
break;
case 0x0a:
PDEBUG(D_PROBE,
@@ -6619,10 +6660,19 @@ static int sd_init(struct gspca_dev *gspca_dev)
sd->ctrls[GAMMA].def = gamma[sd->sensor];
switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ break;
case SENSOR_OV7630C:
- gspca_dev->ctrl_dis = (1 << LIGHTFREQ);
+ gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
+ break;
+ default:
+ gspca_dev->ctrl_dis = (1 << EXPOSURE);
break;
}
+#if AUTOGAIN_DEF
+ if (sd->ctrls[AUTOGAIN].val)
+ gspca_dev->ctrl_inac = (1 << EXPOSURE);
+#endif
/* switch off the led */
reg_w(gspca_dev, 0x01, 0x0000);
@@ -6644,8 +6694,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
{gc0303_Initial, gc0303_InitialScale},
[SENSOR_GC0305] =
{gc0305_Initial, gc0305_InitialScale},
- [SENSOR_HDCS2020b] =
- {hdcs2020b_Initial, hdcs2020b_InitialScale},
+ [SENSOR_HDCS2020] =
+ {hdcs2020_Initial, hdcs2020_InitialScale},
[SENSOR_HV7131B] =
{hv7131b_Initial, hv7131b_InitialScale},
[SENSOR_HV7131R] =
@@ -6739,7 +6789,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* set the gamma tables when not set */
switch (sd->sensor) {
case SENSOR_CS2102K: /* gamma set in xxx_Initial */
- case SENSOR_HDCS2020b:
+ case SENSOR_HDCS2020:
case SENSOR_OV7630C:
break;
default:
@@ -6768,9 +6818,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x40, 0x0117);
break;
case SENSOR_HV7131R:
- i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */
- i2c_write(gspca_dev, 0x26, 0x93, 0x00);
- i2c_write(gspca_dev, 0x27, 0xe0, 0x00);
+ if (!sd->ctrls[AUTOGAIN].val)
+ setexposure(gspca_dev);
reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
break;
case SENSOR_GC0305:
@@ -6848,6 +6897,23 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->ctrls[AUTOGAIN].val = val;
+ if (val) {
+ gspca_dev->ctrl_inac |= (1 << EXPOSURE);
+ } else {
+ gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
+ if (gspca_dev->streaming)
+ getexposure(gspca_dev);
+ }
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{