📄 ov5640.c
字号:
{0x518d, 0x42}, {0x518e, 0x3a}, {0x518f, 0x56}, {0x5190, 0x46}, {0x5191, 0xf0}, {0x5192, 0xf}, {0x5193, 0x70}, {0x5194, 0xf0}, {0x5195, 0xf0}, {0x5196, 0x3}, {0x5197, 0x1}, {0x5198, 0x6}, {0x5199, 0x62}, {0x519a, 0x4}, {0x519b, 0x0}, {0x519c, 0x4}, {0x519d, 0xe7}, {0x519e, 0x38}, };static const struct regval ov5640_qsxga_regs[] = { {0x3820, 0x40}, /* diff. init */ {0x3821, 0x06}, {0x3814, 0x11}, /* image windowing */ {0x3815, 0x11}, {0x3803, 0x00}, {0x3807, 0x9f}, {0x3808, 0x0a}, /* 0x0a20==2592 */ {0x3809, 0x20}, {0x380a, 0x07}, /* 0x798==1944 */ {0x380b, 0x98}, {0x380c, 0x0b}, {0x380d, 0x1c}, {0x380e, 0x07}, {0x380f, 0xb0}, {0x3813, 0x04}, {0x3618, 0x04}, {0x3612, 0x4b}, {0x3708, 0x21}, {0x3709, 0x12}, {0x370c, 0x00}, {0x3a02, 0x07}, /* night mode */ {0x3a03, 0xb0}, {0x3a0e, 0x06}, {0x3a0d, 0x08}, {0x3a14, 0x07}, {0x3a15, 0xb0}, {0x4004, 0x06}, /* BLC line number */ {0x5000, 0x07}, /* black/white pixel cancell, color interp. enable */ {0x5181, 0x52}, /* AWB */ {0x5182, 0x00}, {0x5197, 0x01}, {0x519e, 0x38}, {0x3035, 0x21}, /* SC PLL */ {0x5000, 0x27}, {0x5001, 0x83}, /* special effect, color matrix, AWB enable */ {0x3035, 0x71}, {0x4713, 0x02}, /* jpeg mode 2 */ {0x3036, 0x69}, {0x4407, 0x0c}, /* jpeg ctrl */ {0x460b, 0x37}, {0x460c, 0x20}, {0x3824, 0x01}, {0x4005, 0x1A},};/*static const struct regval ov5640_qsxga_to_qvga_regs[] = {};*/static const struct regval ov5640_qsxga_to_vga_regs[] = { {0x3800, 0x00}, /* image windowing */ {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0xA }, {0x3805, 0x3f}, {0x3806, 0x7 }, {0x3807, 0x9f}, {0x3808, 0x2 }, /* 0x280== 640*/ {0x3809, 0x80}, {0x380a, 0x1 }, /* 0x1e0== 480*/ {0x380b, 0xe0}, {0x380c, 0xc }, {0x380d, 0x80}, {0x380e, 0x7 }, {0x380f, 0xd0}, {0x5001, 0xa3}, /* SDE, scaling, color matrix, AWB enable */ {0x5680, 0x0 }, /* AVG ctrl */ {0x5681, 0x0 }, {0x5682, 0xA }, {0x5683, 0x20}, {0x5684, 0x0 }, {0x5685, 0x0 }, {0x5686, 0x7 }, {0x5687, 0x98},};static const struct regval ov5640_qsxga_to_xga_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0xA }, {0x3805, 0x3f}, {0x3806, 0x7 }, {0x3807, 0x9f}, {0x3808, 0x4 }, /* 0x400==1024 */ {0x3809, 0x0 }, {0x380a, 0x3 }, /* 0x300== 768*/ {0x380b, 0x0 }, {0x380c, 0xc }, {0x380d, 0x80}, {0x380e, 0x7 }, {0x380f, 0xd0}, {0x5001, 0xa3}, {0x5680, 0x0 }, {0x5681, 0x0 }, {0x5682, 0xA }, {0x5683, 0x20}, {0x5684, 0x0 }, {0x5685, 0x0 }, {0x5686, 0x7 }, {0x5687, 0x98},};static const struct regval ov5640_qsxga_to_sxga_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0xA }, {0x3805, 0x3f}, {0x3806, 0x7 }, {0x3807, 0x9f}, {0x3808, 0x5 }, /* 0x500==1280 */ {0x3809, 0x0 }, {0x380a, 0x3 }, /* 0x3c0==960 */ {0x380b, 0xc0}, {0x380c, 0xc }, {0x380d, 0x80}, {0x380e, 0x7 }, {0x380f, 0xd0}, {0x5001, 0xa3}, {0x5680, 0x0 }, {0x5681, 0x0 }, {0x5682, 0xA }, {0x5683, 0x20}, {0x5684, 0x0 }, {0x5685, 0x0 }, {0x5686, 0x7 }, {0x5687, 0x98},};static const struct regval ov5640_qsxga_to_uxga_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0xA }, {0x3805, 0x3f}, {0x3806, 0x7 }, {0x3807, 0x9f}, {0x3808, 0x6 }, /* 0x640== 1600*/ {0x3809, 0x40}, {0x380a, 0x4 }, /* 0x4b0==1200 */ {0x380b, 0xb0}, {0x380c, 0xc }, {0x380d, 0x80}, {0x380e, 0x7 }, {0x380f, 0xd0}, {0x5001, 0xa3}, {0x5680, 0x0 }, {0x5681, 0x0 }, {0x5682, 0xA }, {0x5683, 0x20}, {0x5684, 0x0 }, {0x5685, 0x0 }, {0x5686, 0x7 }, {0x5687, 0x98},};static const struct regval ov5640_qsxga_to_qxga_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0xA }, {0x3805, 0x3f}, {0x3806, 0x7 }, {0x3807, 0x9f}, {0x3808, 0x8 }, /* 0x800==2048 */ {0x3809, 0x0 }, {0x380a, 0x6 }, /* 0x600==1536 */ {0x380b, 0x0 }, {0x380c, 0xc }, {0x380d, 0x80}, {0x380e, 0x7 }, {0x380f, 0xd0}, {0x5001, 0xa3}, {0x5680, 0x0 }, {0x5681, 0x0 }, {0x5682, 0xA }, {0x5683, 0x20}, {0x5684, 0x0 }, {0x5685, 0x0 }, {0x5686, 0x7 }, {0x5687, 0x98},};#if 0static const struct v4l2_queryctrl ov5640_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Flip Vertically", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, }, { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Flip Horizontally", .minimum = 0, .maximum = 1, .step = 1, .default_value = 0, },};#endif/* QVGA: 320*240 */ /*static const struct ov5640_win_size ov5640_win_qvga = { .name = "QVGA", .width = QVGA_WIDTH, .height = QVGA_HEIGHT, .regs = ov5640_qsxga_to_qvga_regs,};*/static const struct ov5640_win_size ov5640_wins[] = { { .name = "VGA", /* VGA: 640*480 */ .resv = RESV_VGA, .width = VGA_WIDTH, .height = VGA_HEIGHT, .regs = ov5640_qsxga_to_vga_regs, }, { .name = "XGA", /* XGA: 1024*768 */ .resv = RESV_XGA, .width = XGA_WIDTH, .height = XGA_HEIGHT, .regs = ov5640_qsxga_to_xga_regs, }, { .name = "SXGA", /* SXGA: 1280*960 */ .resv = RESV_SXGA, .width = SXGA_WIDTH, .height = SXGA_HEIGHT, .regs = ov5640_qsxga_to_sxga_regs, }, { .name = "UXGA", /* UXGA: 1600*1200 */ .resv = RESV_UXGA, .width = UXGA_WIDTH, .height = UXGA_HEIGHT, .regs = ov5640_qsxga_to_uxga_regs, }, { .name = "QXGA", /* QXGA: 2048*1536 */ .resv = RESV_QXGA, .width = QXGA_WIDTH, .height = QXGA_HEIGHT, .regs = ov5640_qsxga_to_qxga_regs, }, { .name = "QSXGA", /* QSXGA: 2560*1920*/ .resv = RESV_QSXGA, .width = QSXGA_WIDTH, .height = QSXGA_HEIGHT, .regs = ov5640_qsxga_regs, },};/* * supported color format list */static const struct ov5640_color_format ov5640_cfmts[] = { { .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, .colorspace = V4L2_COLORSPACE_JPEG, }, { .code = V4L2_MBUS_FMT_YUYV8_2X8_LE, .colorspace = V4L2_COLORSPACE_JPEG, },};static int i2cc_get_reg(struct i2c_client *client, unsigned short reg, unsigned char *value){ unsigned char buffer[2]; int ret = 0; int err = 0; buffer[0] = (reg >> 8) & 0xFF; buffer[1] = reg & 0xFF; if (2 != (ret = i2c_master_send(client, buffer, 2))) { err = -2; OV_ERR("i2cc out error: ret == %d (should be 2)\n", ret); } if (1 != (ret = i2c_master_recv(client, buffer, 1))) { err = -1; OV_ERR("i2cc in error: ret == %d (should be 1)\n", ret); } //OV_INFO("ov5640 client: read 0x%x = 0x%x\n", reg, buffer[0]); *value = buffer[0]; return (err);}static int i2cc_set_reg(struct i2c_client *client, unsigned short reg, unsigned char value){ unsigned char buffer[3]; int ret = 0; int err = 0; buffer[0] = (reg >> 8) & 0xFF; buffer[1] = reg & 0xFF; buffer[2] = value; //OV_INFO("ov5640 client: writing 0x%x = 0x%x\n", reg, value); if (3 != (ret = i2c_master_send(client, buffer, 3))) { OV_ERR("i2cc out error: ret = %d (should be 3)\n", ret); err = -3; } return (err);}static inline struct ov5640_priv *to_ov5640(const struct i2c_client *client){ return container_of(i2c_get_clientdata(client), struct ov5640_priv, subdev);}static int write_regs(struct i2c_client *client, const struct regval *regs, int array_len){ int i; int ret = 0; for (i = 0; i < array_len; i++) { if ((ret = i2cc_set_reg(client, regs->reg, regs->val))) { OV_ERR("error to set reg:0x%d -> value:%d(index:%d)\n", regs->reg, regs->val, i); break; } regs++; } INFO_BLUE("------*------- write array regs over -------*------ \n"); return (ret);}static int ov5640_set_bus_param(struct soc_camera_device *icd, unsigned long flags){ INFO_PURLPLE("\n"); return 0;}static unsigned long ov5640_query_bus_param(struct soc_camera_device *icd){ struct soc_camera_link *icl = to_soc_camera_link(icd); /* camera can do 10 bit transfers, but omit it now */ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; return soc_camera_apply_sensor_flags(icl, flags);}static int ov5640_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id){ struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5640_priv *priv = to_ov5640(client); id->ident = priv->model; id->revision = 0; return (0);}static const struct ov5640_win_size *select_win( unsigned int width, unsigned int height){ const struct ov5640_win_size *ret = NULL; int size = ARRAY_SIZE(ov5640_wins); unsigned int diff = -1; unsigned int tmp; int i; for (i = 0; i < size; i++) { tmp = abs(width - ov5640_wins[i].width) + abs(height - ov5640_wins[i].height); if (tmp < diff) { diff = tmp; ret = ov5640_wins + i; } } return (ret); }static int ov5640_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *vmf){ struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5640_priv *priv = to_ov5640(client); const struct ov5640_win_size *win; int found = 0; int i; win = select_win(vmf->width, vmf->height); vmf->width = win->width; vmf->height = win->height; vmf->field = V4L2_FIELD_NONE; for (i = 0; i < ARRAY_SIZE(ov5640_cfmts); i++) { if (ov5640_cfmts[i].code == vmf->code) { found = 1; break; } } if (found) { vmf->colorspace = ov5640_cfmts[i].colorspace; } else { /* Unsupported format requested. Propose either */ if (priv->cfmt) { /* the current one or */ vmf->colorspace = priv->cfmt->colorspace; vmf->code = priv->cfmt->code; } else { /* the default one */ vmf->colorspace = ov5640_cfmts[0].colorspace; vmf->code = ov5640_cfmts[0].code; } } INFO_GREEN("code:%d-%s %dX%d\n", vmf->code, win->name, vmf->width, vmf->height); return (0);}/* start or stop streaming from the device */static int ov5640_s_stream(struct v4l2_subdev *sd, int enable){ struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5640_priv *priv = to_ov5640(client); if (!enable) { INFO_PURLPLE("stream down\n"); // set regs to enter sleep mode, already in DVP mode i2cc_set_reg(client, 0x3008, 0x42); return (0); } if (NULL == priv->win || NULL == priv->cfmt) { OV_ERR("win or cfmt select error!\n"); return (-EPERM); } INFO_PURLPLE("stream on\n"); //set regs to leave sleep mode, in DVP mode , needn't to set 0x300e to 0xc i2cc_set_reg(client, 0x3008, 0x02); INFO_GREEN("format: %d, win:%s\n", priv->cfmt->code, priv->win->name); // wait for 2 Vsync, and capture the 3rd frame, (1 / 7.5) * 2 =. 267ms mdelay(270); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -