ret = i2c_transfer(client->adapter, &msg, 1); if (ret < 0) {
dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); return ret;
}
/* we have to read the register back ... no idea why, maybe HW bug */
ret = ov9640_reg_read(client, reg, &_val); if (ret)
dev_err(&client->dev, "Failed reading back register 0x%02x!\n", reg);
return 0;
}
/* Read a register, alter its bits, write it back */ staticint ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
{
u8 val; int ret;
ret = ov9640_reg_read(client, reg, &val); if (ret) {
dev_err(&client->dev, "[Read]-Modify-Write of register %02x failed!\n", reg); return ret;
}
val |= set;
val &= ~unset;
ret = ov9640_reg_write(client, reg, val); if (ret)
dev_err(&client->dev, "Read-Modify-[Write] of register %02x failed!\n", reg);
return ret;
}
/* Soft reset the camera. This has nothing to do with the RESET pin! */ staticint ov9640_reset(struct i2c_client *client)
{ int ret;
ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); if (ret)
dev_err(&client->dev, "An error occurred while entering soft reset!\n");
return ret;
}
/* Start/Stop streaming from the device */ staticint ov9640_s_stream(struct v4l2_subdev *sd, int enable)
{ return 0;
}
/* Set status of additional camera capabilities */ staticint ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
{ struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP,
OV9640_MVFP_V, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); case V4L2_CID_HFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP,
OV9640_MVFP_H, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
}
/* Setup registers according to resolution and color encoding */ staticint ov9640_write_regs(struct i2c_client *client, u32 width,
u32 code, struct ov9640_reg_alt *alts)
{ conststruct ov9640_reg *ov9640_regs, *matrix_regs; unsignedint ov9640_regs_len, matrix_regs_len; unsignedint i; int ret;
u8 val;
/* select register configuration for given resolution */ switch (width) { case W_QQCIF:
ov9640_regs = ov9640_regs_qqcif;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif); break; case W_QQVGA:
ov9640_regs = ov9640_regs_qqvga;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga); break; case W_QCIF:
ov9640_regs = ov9640_regs_qcif;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif); break; case W_QVGA:
ov9640_regs = ov9640_regs_qvga;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga); break; case W_CIF:
ov9640_regs = ov9640_regs_cif;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif); break; case W_VGA:
ov9640_regs = ov9640_regs_vga;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga); break; case W_SXGA:
ov9640_regs = ov9640_regs_sxga;
ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga); break; default:
dev_err(&client->dev, "Failed to select resolution!\n"); return -EINVAL;
}
/* select color matrix configuration for given color encoding */ if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
matrix_regs = ov9640_regs_rgb;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
}
/* write register settings into the module */ for (i = 0; i < ov9640_regs_len; i++) {
val = ov9640_regs[i].val;
switch (ov9640_regs[i].reg) { case OV9640_COM7:
val |= alts->com7; break; case OV9640_COM12:
val |= alts->com12; break; case OV9640_COM13:
val |= alts->com13; break; case OV9640_COM15:
val |= alts->com15; break;
}
ret = ov9640_reg_write(client, ov9640_regs[i].reg, val); if (ret) return ret;
}
/* write color matrix configuration into the module */ for (i = 0; i < matrix_regs_len; i++) {
ret = ov9640_reg_write(client, matrix_regs[i].reg,
matrix_regs[i].val); if (ret) return ret;
}
return 0;
}
/* program default register values */ staticint ov9640_prog_dflt(struct i2c_client *client)
{ unsignedint i; int ret;
for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
ov9640_regs_dflt[i].val); if (ret) return ret;
}
/* wait for the changes to actually happen, 140ms are not enough yet */
msleep(150);
return 0;
}
/* set the format we will capture in */ staticint ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
{ struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov9640_reg_alt alts = {0}; int ret;
ov9640_alter_regs(mf->code, &alts);
ov9640_reset(client);
ret = ov9640_prog_dflt(client); if (ret) return ret;
ret = ov9640_s_power(&priv->subdev, 1); if (ret < 0) return ret;
/* * check and show product ID and manufacturer ID
*/
ret = ov9640_reg_read(client, OV9640_PID, &pid); if (!ret)
ret = ov9640_reg_read(client, OV9640_VER, &ver); if (!ret)
ret = ov9640_reg_read(client, OV9640_MIDH, &midh); if (!ret)
ret = ov9640_reg_read(client, OV9640_MIDL, &midl); if (ret) goto done;
switch (VERSION(pid, ver)) { case OV9640_V2:
devname = "ov9640";
priv->revision = 2; break; case OV9640_V3:
devname = "ov9640";
priv->revision = 3; break; default:
dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
ret = -ENODEV; goto done;
}
dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
devname, pid, ver, midh, midl);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.