static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win) { int qvga = win->quarter; /******** QVGA-specific regs ********/ ov_write(c, 0x14, qvga?0xa4:0x84); /******** Palette-specific regs ********/ if (win->format == VIDEO_PALETTE_GREY) { ov_write_mask(c, 0x0e, 0x40, 0x40); ov_write_mask(c, 0x13, 0x20, 0x20); } else { ov_write_mask(c, 0x0e, 0x00, 0x40); ov_write_mask(c, 0x13, 0x00, 0x20); } /******** Clock programming ********/ ov_write(c, 0x11, win->clockdiv); /******** Resolution-specific ********/ if (win->width == 640 && win->height == 480) ov_write(c, 0x35, 0x9e); else ov_write(c, 0x35, 0x1e); return 0; }
static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win) { int qvga = win->quarter; ov_write(c, 0x14, qvga?0xa4:0x84); if (win->format == VIDEO_PALETTE_GREY) { ov_write_mask(c, 0x0e, 0x40, 0x40); ov_write_mask(c, 0x13, 0x20, 0x20); } else { ov_write_mask(c, 0x0e, 0x00, 0x40); ov_write_mask(c, 0x13, 0x00, 0x20); } ov_write(c, 0x11, win->clockdiv); if (win->width == 640 && win->height == 480) ov_write(c, 0x35, 0x9e); else ov_write(c, 0x35, 0x1e); return 0; }
static int ov76be_set_control(struct i2c_client *c, struct ovcamchip_control *ctl) { struct ovcamchip *ov = i2c_get_clientdata(c); struct ov76be *s = ov->spriv; int rc; int v = ctl->value; switch (ctl->id) { case OVCAMCHIP_CID_BRIGHT: rc = ov_write(c, REG_BRT, v >> 8); break; case OVCAMCHIP_CID_SAT: rc = ov_write(c, REG_SAT, v >> 8); break; case OVCAMCHIP_CID_EXP: rc = ov_write(c, REG_EXP, v); break; case OVCAMCHIP_CID_FREQ: { int sixty = (v == 60); rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80); if (rc < 0) goto out; rc = ov_write(c, 0x2b, sixty?0x00:0xac); if (rc < 0) goto out; rc = ov_write_mask(c, 0x76, 0x01, 0x01); break; } case OVCAMCHIP_CID_BANDFILT: rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04); s->bandfilt = v; break; case OVCAMCHIP_CID_AUTOBRIGHT: rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10); s->auto_brt = v; break; case OVCAMCHIP_CID_AUTOEXP: rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01); s->auto_exp = v; break; case OVCAMCHIP_CID_MIRROR: rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40); s->mirror = v; break; default: DDEBUG(2, &c->dev, "control not supported: %d", ctl->id); return -EPERM; } out: DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc); return rc; }
/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure. */ static int init_camchip(struct i2c_client *c) { int i, success; unsigned char high, low; /* Reset the chip */ ov_write(c, 0x12, 0x80); /* Wait for it to initialize */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1 + 150 * HZ / 1000); for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) { if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) { if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) { if (high == 0x7F && low == 0xA2) { success = 1; continue; } } } /* Reset the chip */ ov_write(c, 0x12, 0x80); /* Wait for it to initialize */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1 + 150 * HZ / 1000); /* Dummy read to sync I2C */ ov_read(c, 0x00, &low); } if (!success) return -EIO; PDEBUG(1, "I2C synced in %d attempt(s)", i); return 0; }
int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals) { int rc; while (rvals->reg != 0xff) { rc = ov_write(c, rvals->reg, rvals->val); if (rc < 0) return rc; rvals++; } return 0; }
static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win) { /******** QCIF-specific regs ********/ ov_write(c, 0x14, win->quarter?0x24:0x04); /******** Palette-specific regs ********/ /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */ if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) { if (win->format == VIDEO_PALETTE_GREY) ov_write_mask(c, 0x13, 0x00, 0x20); else ov_write_mask(c, 0x13, 0x20, 0x20); } else { if (win->format == VIDEO_PALETTE_GREY) ov_write_mask(c, 0x13, 0x20, 0x20); else ov_write_mask(c, 0x13, 0x00, 0x20); } /******** Clock programming ********/ /* The OV6620 needs special handling. This prevents the * severe banding that normally occurs */ /* Clock down */ ov_write(c, 0x2a, 0x04); ov_write(c, 0x11, win->clockdiv); ov_write(c, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */ return 0; }
/* Writes bits at positions specified by mask to an I2C reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value". */ int ov_write_mask(struct i2c_client *c, unsigned char reg, unsigned char value, unsigned char mask) { int rc; unsigned char oldval, newval; if (mask == 0xff) { newval = value; } else { rc = ov_read(c, reg, &oldval); if (rc < 0) return rc; oldval &= (~mask); /* Clear the masked bits */ value &= mask; /* Enforce mask on value */ newval = oldval | value; /* Set the desired bits */ } return ov_write(c, reg, newval); }