[media] gspca - ov519: New sensor ov7660 with bridge ov530 (ov519)

[mchehab@redhat.com: Some CodingStyle fixes]
Tested-by: Anca Emanuel <anca.emanuel@gmail.com>
Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jean-François Moine 2010-11-13 05:10:27 -03:00 committed by Mauro Carvalho Chehab
parent 7491f785dd
commit 42e142f6b7
1 changed files with 386 additions and 8 deletions

View File

@ -82,7 +82,7 @@ struct sd {
#define BRIDGE_OV511PLUS 1 #define BRIDGE_OV511PLUS 1
#define BRIDGE_OV518 2 #define BRIDGE_OV518 2
#define BRIDGE_OV518PLUS 3 #define BRIDGE_OV518PLUS 3
#define BRIDGE_OV519 4 #define BRIDGE_OV519 4 /* = ov530 */
#define BRIDGE_OVFX2 5 #define BRIDGE_OVFX2 5
#define BRIDGE_W9968CF 6 #define BRIDGE_W9968CF 6
#define BRIDGE_MASK 7 #define BRIDGE_MASK 7
@ -127,6 +127,7 @@ enum sensors {
SEN_OV7620AE, SEN_OV7620AE,
SEN_OV7640, SEN_OV7640,
SEN_OV7648, SEN_OV7648,
SEN_OV7660,
SEN_OV7670, SEN_OV7670,
SEN_OV76BE, SEN_OV76BE,
SEN_OV8610, SEN_OV8610,
@ -183,7 +184,7 @@ static const struct ctrl sd_ctrls[] = {
}, },
.set_control = setcolors, .set_control = setcolors,
}, },
/* The flip controls work with ov7670 only */ /* The flip controls work for sensors ov7660 and ov7670 only */
[HFLIP] = { [HFLIP] = {
{ {
.id = V4L2_CID_HFLIP, .id = V4L2_CID_HFLIP,
@ -268,6 +269,8 @@ static const unsigned ctrl_dis[] = {
(1 << AUTOBRIGHT) | (1 << AUTOBRIGHT) |
(1 << CONTRAST), (1 << CONTRAST),
[SEN_OV7660] = (1 << AUTOBRIGHT),
[SEN_OV7670] = (1 << COLORS) | [SEN_OV7670] = (1 << COLORS) |
(1 << AUTOBRIGHT), (1 << AUTOBRIGHT),
@ -572,7 +575,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */ #define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
#define OV7610_REG_COM_I 0x29 /* misc settings */ #define OV7610_REG_COM_I 0x29 /* misc settings */
/* OV7670 registers */ /* OV7660 and OV7670 registers */
#define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ #define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
#define OV7670_R01_BLUE 0x01 /* blue gain */ #define OV7670_R01_BLUE 0x01 /* blue gain */
#define OV7670_R02_RED 0x02 /* red gain */ #define OV7670_R02_RED 0x02 /* red gain */
@ -625,6 +628,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
/*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */ /*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */
#define OV7670_R41_COM16 0x41 /* Control 16 */ #define OV7670_R41_COM16 0x41 /* Control 16 */
#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */ #define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
/* end of ov7660 common registers */
#define OV7670_R55_BRIGHT 0x55 /* Brightness */ #define OV7670_R55_BRIGHT 0x55 /* Brightness */
#define OV7670_R56_CONTRAS 0x56 /* Contrast control */ #define OV7670_R56_CONTRAS 0x56 /* Contrast control */
#define OV7670_R69_GFIX 0x69 /* Fix gain control */ #define OV7670_R69_GFIX 0x69 /* Fix gain control */
@ -1577,6 +1581,150 @@ static const struct ov_i2c_regvals norm_7640[] = {
{ 0x12, 0x14 }, { 0x12, 0x14 },
}; };
static const struct ov_regvals init_519_ov7660[] = {
{ 0x5d, 0x03 }, /* Turn off suspend mode */
{ 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */
{ 0x54, 0x0f }, /* bit2 (jpeg enable) */
{ 0xa2, 0x20 }, /* a2-a5 are undocumented */
{ 0xa3, 0x18 },
{ 0xa4, 0x04 },
{ 0xa5, 0x28 },
{ 0x37, 0x00 }, /* SetUsbInit */
{ 0x55, 0x02 }, /* 4.096 Mhz audio clock */
/* Enable both fields, YUV Input, disable defect comp (why?) */
{ 0x20, 0x0c }, /* 0x0d does U <-> V swap */
{ 0x21, 0x38 },
{ 0x22, 0x1d },
{ 0x17, 0x50 }, /* undocumented */
{ 0x37, 0x00 }, /* undocumented */
{ 0x40, 0xff }, /* I2C timeout counter */
{ 0x46, 0x00 }, /* I2C clock prescaler */
};
static const struct ov_i2c_regvals norm_7660[] = {
{OV7670_R12_COM7, OV7670_COM7_RESET},
{OV7670_R11_CLKRC, 0x81},
{0x92, 0x00}, /* DM_LNL */
{0x93, 0x00}, /* DM_LNH */
{0x9d, 0x4c}, /* BD50ST */
{0x9e, 0x3f}, /* BD60ST */
{OV7670_R3B_COM11, 0x02},
{OV7670_R13_COM8, 0xf5},
{OV7670_R10_AECH, 0x00},
{OV7670_R00_GAIN, 0x00},
{OV7670_R01_BLUE, 0x7c},
{OV7670_R02_RED, 0x9d},
{OV7670_R12_COM7, 0x00},
{OV7670_R04_COM1, 00},
{OV7670_R18_HSTOP, 0x01},
{OV7670_R17_HSTART, 0x13},
{OV7670_R32_HREF, 0x92},
{OV7670_R19_VSTART, 0x02},
{OV7670_R1A_VSTOP, 0x7a},
{OV7670_R03_VREF, 0x00},
{OV7670_R0E_COM5, 0x04},
{OV7670_R0F_COM6, 0x62},
{OV7670_R15_COM10, 0x00},
{0x16, 0x02}, /* RSVD */
{0x1b, 0x00}, /* PSHFT */
{OV7670_R1E_MVFP, 0x01},
{0x29, 0x3c}, /* RSVD */
{0x33, 0x00}, /* CHLF */
{0x34, 0x07}, /* ARBLM */
{0x35, 0x84}, /* RSVD */
{0x36, 0x00}, /* RSVD */
{0x37, 0x04}, /* ADC */
{0x39, 0x43}, /* OFON */
{OV7670_R3A_TSLB, 0x00},
{OV7670_R3C_COM12, 0x6c},
{OV7670_R3D_COM13, 0x98},
{OV7670_R3F_EDGE, 0x23},
{OV7670_R40_COM15, 0xc1},
{OV7670_R41_COM16, 0x22},
{0x6b, 0x0a}, /* DBLV */
{0xa1, 0x08}, /* RSVD */
{0x69, 0x80}, /* HV */
{0x43, 0xf0}, /* RSVD.. */
{0x44, 0x10},
{0x45, 0x78},
{0x46, 0xa8},
{0x47, 0x60},
{0x48, 0x80},
{0x59, 0xba},
{0x5a, 0x9a},
{0x5b, 0x22},
{0x5c, 0xb9},
{0x5d, 0x9b},
{0x5e, 0x10},
{0x5f, 0xe0},
{0x60, 0x85},
{0x61, 0x60},
{0x9f, 0x9d}, /* RSVD */
{0xa0, 0xa0}, /* DSPC2 */
{0x4f, 0x60}, /* matrix */
{0x50, 0x64},
{0x51, 0x04},
{0x52, 0x18},
{0x53, 0x3c},
{0x54, 0x54},
{0x55, 0x40},
{0x56, 0x40},
{0x57, 0x40},
{0x58, 0x0d}, /* matrix sign */
{0x8b, 0xcc}, /* RSVD */
{0x8c, 0xcc},
{0x8d, 0xcf},
{0x6c, 0x40}, /* gamma curve */
{0x6d, 0xe0},
{0x6e, 0xa0},
{0x6f, 0x80},
{0x70, 0x70},
{0x71, 0x80},
{0x72, 0x60},
{0x73, 0x60},
{0x74, 0x50},
{0x75, 0x40},
{0x76, 0x38},
{0x77, 0x3c},
{0x78, 0x32},
{0x79, 0x1a},
{0x7a, 0x28},
{0x7b, 0x24},
{0x7c, 0x04}, /* gamma curve */
{0x7d, 0x12},
{0x7e, 0x26},
{0x7f, 0x46},
{0x80, 0x54},
{0x81, 0x64},
{0x82, 0x70},
{0x83, 0x7c},
{0x84, 0x86},
{0x85, 0x8e},
{0x86, 0x9c},
{0x87, 0xab},
{0x88, 0xc4},
{0x89, 0xd1},
{0x8a, 0xe5},
{OV7670_R14_COM9, 0x1e},
{OV7670_R24_AEW, 0x80},
{OV7670_R25_AEB, 0x72},
{OV7670_R26_VPT, 0xb3},
{0x62, 0x80}, /* LCC1 */
{0x63, 0x80}, /* LCC2 */
{0x64, 0x06}, /* LCC3 */
{0x65, 0x00}, /* LCC4 */
{0x66, 0x01}, /* LCC5 */
{0x94, 0x0e}, /* RSVD.. */
{0x95, 0x14},
{OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT
| 0x10
| OV7670_COM8_AGC
| OV7670_COM8_AWB
| OV7670_COM8_AEC},
{0xa1, 0xc8}
};
/* 7670. Defaults taken from OmniVision provided data, /* 7670. Defaults taken from OmniVision provided data,
* as provided by Jonathan Corbet of OLPC */ * as provided by Jonathan Corbet of OLPC */
static const struct ov_i2c_regvals norm_7670[] = { static const struct ov_i2c_regvals norm_7670[] = {
@ -2574,6 +2722,11 @@ static void ov7xx0_configure(struct sd *sd)
PDEBUG(D_PROBE, "Sensor is an OV7648"); PDEBUG(D_PROBE, "Sensor is an OV7648");
sd->sensor = SEN_OV7648; sd->sensor = SEN_OV7648;
break; break;
case 0x60:
PDEBUG(D_PROBE, "Sensor is a OV7660");
sd->sensor = SEN_OV7660;
sd->invert_led = 0;
break;
default: default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
return; return;
@ -2935,6 +3088,91 @@ static void ovfx2_configure(struct sd *sd)
write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2)); write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
} }
/* set the mode */
/* This function works for ov7660 only */
static void ov519_set_mode(struct sd *sd)
{
static const struct ov_regvals bridge_ov7660[2][10] = {
{{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00},
{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
{0x25, 0x01}, {0x26, 0x00}},
{{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00},
{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
{0x25, 0x03}, {0x26, 0x00}}
};
static const struct ov_i2c_regvals sensor_ov7660[2][3] = {
{{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}},
{{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}}
};
static const struct ov_i2c_regvals sensor_ov7660_2[] = {
{OV7670_R17_HSTART, 0x13},
{OV7670_R18_HSTOP, 0x01},
{OV7670_R32_HREF, 0x92},
{OV7670_R19_VSTART, 0x02},
{OV7670_R1A_VSTOP, 0x7a},
{OV7670_R03_VREF, 0x00},
/* {0x33, 0x00}, */
/* {0x34, 0x07}, */
/* {0x36, 0x00}, */
/* {0x6b, 0x0a}, */
};
write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode],
ARRAY_SIZE(bridge_ov7660[0]));
write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode],
ARRAY_SIZE(sensor_ov7660[0]));
write_i2c_regvals(sd, sensor_ov7660_2,
ARRAY_SIZE(sensor_ov7660_2));
}
/* set the frame rate */
/* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */
static void ov519_set_fr(struct sd *sd)
{
int fr;
u8 clock;
/* frame rate table with indices:
* - mode = 0: 320x240, 1: 640x480
* - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5
* - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock)
*/
static const u8 fr_tb[2][6][3] = {
{{0x04, 0xff, 0x00},
{0x04, 0x1f, 0x00},
{0x04, 0x1b, 0x00},
{0x04, 0x15, 0x00},
{0x04, 0x09, 0x00},
{0x04, 0x01, 0x00}},
{{0x0c, 0xff, 0x00},
{0x0c, 0x1f, 0x00},
{0x0c, 0x1b, 0x00},
{0x04, 0xff, 0x01},
{0x04, 0x1f, 0x01},
{0x04, 0x1b, 0x01}},
};
if (frame_rate > 0)
sd->frame_rate = frame_rate;
if (sd->frame_rate >= 30)
fr = 0;
else if (sd->frame_rate >= 25)
fr = 1;
else if (sd->frame_rate >= 20)
fr = 2;
else if (sd->frame_rate >= 15)
fr = 3;
else if (sd->frame_rate >= 10)
fr = 4;
else
fr = 5;
reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]);
reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]);
clock = fr_tb[sd->gspca_dev.curr_mode][fr][2];
if (sd->sensor == SEN_OV7660)
clock |= 0x80; /* enable double clock */
ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
}
/* this function is called at probe time */ /* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev, static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id) const struct usb_device_id *id)
@ -3118,6 +3356,34 @@ static int sd_init(struct gspca_dev *gspca_dev)
case SEN_OV7648: case SEN_OV7648:
write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)); write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640));
break; break;
case SEN_OV7660:
i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET);
msleep(14);
reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
write_regvals(sd, init_519_ov7660,
ARRAY_SIZE(init_519_ov7660));
write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
sd->gspca_dev.curr_mode = 1; /* 640x480 */
sd->frame_rate = 15;
ov519_set_mode(sd);
ov519_set_fr(sd);
sd->ctrls[COLORS].max = 4; /* 0..4 */
sd->ctrls[COLORS].val =
sd->ctrls[COLORS].def = 2;
setcolors(gspca_dev);
sd->ctrls[CONTRAST].max = 6; /* 0..6 */
sd->ctrls[CONTRAST].val =
sd->ctrls[CONTRAST].def = 3;
setcontrast(gspca_dev);
sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */
sd->ctrls[BRIGHTNESS].val =
sd->ctrls[BRIGHTNESS].def = 3;
setbrightness(gspca_dev);
sd_reset_snapshot(gspca_dev);
ov51x_restart(sd);
ov51x_stop(sd); /* not in win traces */
ov51x_led_control(sd, 0);
break;
case SEN_OV7670: case SEN_OV7670:
sd->ctrls[FREQ].max = 3; /* auto */ sd->ctrls[FREQ].max = 3; /* auto */
sd->ctrls[FREQ].def = 3; sd->ctrls[FREQ].def = 3;
@ -3431,16 +3697,21 @@ static void ov519_mode_init_regs(struct sd *sd)
}; };
/******** Set the mode ********/ /******** Set the mode ********/
if (sd->sensor != SEN_OV7670) { switch (sd->sensor) {
default:
write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519)); write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519));
if (sd->sensor == SEN_OV7640 || if (sd->sensor == SEN_OV7640 ||
sd->sensor == SEN_OV7648) { sd->sensor == SEN_OV7648) {
/* Select 8-bit input mode */ /* Select 8-bit input mode */
reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
} }
} else { break;
case SEN_OV7660:
return; /* done by ov519_set_mode/fr() */
case SEN_OV7670:
write_regvals(sd, mode_init_519_ov7670, write_regvals(sd, mode_init_519_ov7670,
ARRAY_SIZE(mode_init_519_ov7670)); ARRAY_SIZE(mode_init_519_ov7670));
break;
} }
reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4);
@ -3682,6 +3953,7 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
i2c_w(sd, 0x11, sd->clockdiv); i2c_w(sd, 0x11, sd->clockdiv);
} }
/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */
static void sethvflip(struct gspca_dev *gspca_dev) static void sethvflip(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
@ -3703,11 +3975,18 @@ static void set_ov_sensor_window(struct sd *sd)
int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
/* mode setup is fully handled in mode_init_ov_sensor_regs for these */ /* mode setup is fully handled in mode_init_ov_sensor_regs for these */
if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610 || switch (sd->sensor) {
sd->sensor == SEN_OV7670) { case SEN_OV2610:
case SEN_OV3610:
case SEN_OV7670:
mode_init_ov_sensor_regs(sd); mode_init_ov_sensor_regs(sd);
return; return;
case SEN_OV7660:
ov519_set_mode(sd);
ov519_set_fr(sd);
return;
} }
gspca_dev = &sd->gspca_dev; gspca_dev = &sd->gspca_dev;
qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2; crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2;
@ -4101,6 +4380,22 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
int val; int val;
static const struct ov_i2c_regvals brit_7660[][7] = {
{{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90},
{0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}},
{{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1},
{0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}},
{{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2},
{0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}},
{{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3},
{0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}},
{{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3},
{0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}},
{{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3},
{0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}},
{{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4},
{0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}}
};
val = sd->ctrls[BRIGHTNESS].val; val = sd->ctrls[BRIGHTNESS].val;
switch (sd->sensor) { switch (sd->sensor) {
@ -4120,6 +4415,10 @@ static void setbrightness(struct gspca_dev *gspca_dev)
if (!sd->ctrls[AUTOBRIGHT].val) if (!sd->ctrls[AUTOBRIGHT].val)
i2c_w(sd, OV7610_REG_BRT, val); i2c_w(sd, OV7610_REG_BRT, val);
break; break;
case SEN_OV7660:
write_i2c_regvals(sd, brit_7660[val],
ARRAY_SIZE(brit_7660[0]));
break;
case SEN_OV7670: case SEN_OV7670:
/*win trace /*win trace
* i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */ * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */
@ -4132,6 +4431,64 @@ static void setcontrast(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
int val; int val;
static const struct ov_i2c_regvals contrast_7660[][31] = {
{{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0},
{0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30},
{0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24},
{0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34},
{0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65},
{0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83},
{0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f},
{0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}},
{{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94},
{0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30},
{0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24},
{0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31},
{0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62},
{0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81},
{0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1},
{0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}},
{{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84},
{0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40},
{0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24},
{0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34},
{0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d},
{0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81},
{0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e},
{0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}},
{{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70},
{0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48},
{0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34},
{0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22},
{0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58},
{0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80},
{0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9},
{0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}},
{{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80},
{0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60},
{0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38},
{0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e},
{0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46},
{0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c},
{0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4},
{0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}},
{{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80},
{0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30},
{0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50},
{0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08},
{0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a},
{0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b},
{0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3},
{0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}},
{{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60},
{0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8},
{0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c},
{0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04},
{0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22},
{0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b},
{0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde},
{0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}},
};
val = sd->ctrls[CONTRAST].val; val = sd->ctrls[CONTRAST].val;
switch (sd->sensor) { switch (sd->sensor) {
@ -4163,6 +4520,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, 0x64, ctab[val >> 4]); i2c_w(sd, 0x64, ctab[val >> 4]);
break; break;
} }
case SEN_OV7660:
write_i2c_regvals(sd, contrast_7660[val],
ARRAY_SIZE(contrast_7660[0]));
break;
case SEN_OV7670: case SEN_OV7670:
/* check that this isn't just the same as ov7610 */ /* check that this isn't just the same as ov7610 */
i2c_w(sd, OV7670_R56_CONTRAS, val >> 1); i2c_w(sd, OV7670_R56_CONTRAS, val >> 1);
@ -4174,6 +4535,18 @@ static void setcolors(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
int val; int val;
static const struct ov_i2c_regvals colors_7660[][6] = {
{{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a},
{0x53, 0x19}, {0x54, 0x23}},
{{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11},
{0x53, 0x2c}, {0x54, 0x3e}},
{{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19},
{0x53, 0x40}, {0x54, 0x59}},
{{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20},
{0x53, 0x53}, {0x54, 0x73}},
{{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28},
{0x53, 0x66}, {0x54, 0x8e}},
};
val = sd->ctrls[COLORS].val; val = sd->ctrls[COLORS].val;
switch (sd->sensor) { switch (sd->sensor) {
@ -4197,6 +4570,10 @@ static void setcolors(struct gspca_dev *gspca_dev)
case SEN_OV7648: case SEN_OV7648:
i2c_w(sd, OV7610_REG_SAT, val & 0xf0); i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
break; break;
case SEN_OV7660:
write_i2c_regvals(sd, colors_7660[val],
ARRAY_SIZE(colors_7660[0]));
break;
case SEN_OV7670: case SEN_OV7670:
/* supported later once I work out how to do it /* supported later once I work out how to do it
* transparently fail now! */ * transparently fail now! */
@ -4214,7 +4591,8 @@ static void setautobright(struct gspca_dev *gspca_dev)
static void setfreq_i(struct sd *sd) static void setfreq_i(struct sd *sd)
{ {
if (sd->sensor == SEN_OV7670) { if (sd->sensor == SEN_OV7660
|| sd->sensor == SEN_OV7670) {
switch (sd->ctrls[FREQ].val) { switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */ case 0: /* Banding filter disabled */
i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT); i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT);