⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ov5640.c

📁 linux下ov5640驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
static int reset_ov5640(struct i2c_client *client){	int ret = i2cc_set_reg(client, 0x3008, 0x82);	mdelay(5);	return (ret);}static int ov5640_get_params(struct i2c_client *client, unsigned int *width,     unsigned int *height, enum v4l2_mbus_pixelcode code){    struct ov5640_priv *priv = to_ov5640(client);    int ret = -EINVAL;    int i;    /* select format */    priv->cfmt = NULL;    for (i = 0; i < ARRAY_SIZE(ov5640_cfmts); i++) {        if (code == ov5640_cfmts[i].code) {            priv->cfmt = ov5640_cfmts + i;            break;        }    }    if (NULL == priv->cfmt) {        return (ret);    }    priv->win = select_win(*width, *height);    *width = priv->win->width;    *height = priv->win->height;    INFO_PURLPLE("current params: %s %dX%d\n",         priv->win->name, *width, *height);    return (0);}static inline void init_setting_values(struct ov5640_priv *priv){    priv->flip_flag = OV5640_HFLIP; }static void get_preview_params(struct i2c_client *client,     unsigned int *exposure, unsigned short *maxlines, unsigned short *gain){    unsigned char ret_h = 0;    unsigned char ret_m = 0;    unsigned char ret_l = 0;    i2cc_get_reg(client, 0x3500, &ret_h);    i2cc_get_reg(client, 0x3501, &ret_m);    i2cc_get_reg(client, 0x3502, &ret_l);    *exposure = ((ret_h << 16) + (ret_m << 8) + ret_l) >> 4;    INFO_GREEN("expl:0x%x, expm:0x%x, exph:0x%x\n",             ret_l, ret_m, ret_h);    i2cc_get_reg(client, 0x350c, &ret_h);    i2cc_get_reg(client, 0x350d, &ret_l);    *maxlines = (ret_h << 8) + ret_l;    //i2cc_get_reg(client, 0x350a, &ret_h);    i2cc_get_reg(client, 0x350b, &ret_l);    *gain = /*((ret_h & 0x1) << 8) + */ret_l;    INFO_GREEN("exposure:0x%x, maxlines:0x%x, gain:0x%x\n",        *exposure, *maxlines, *gain);}static void manual_set_exposure_and_gain(struct i2c_client *client,    unsigned int p_exposure, unsigned short p_maxlines, unsigned short p_gain){    unsigned char ret_h = 0;    unsigned char ret_l = 0;    unsigned char exp_h;    unsigned char exp_m;    unsigned char exp_l;    unsigned char lines_10ms;    unsigned short cap_maxlines;    unsigned short cap_exposure;    unsigned short cap_gain;    unsigned short gain;    unsigned int   cap_exp_gain;    i2cc_get_reg(client, 0x350c, &ret_h);    i2cc_get_reg(client, 0x350d, &ret_l);    cap_maxlines = (ret_h << 8) + ret_l;    //p_maxlines = 980;    //cap_maxlines = 1964;    INFO_GREEN("cap_maxlines: 0x%x\n", cap_maxlines);        // for 50HZ, if 60HZ, devided by 12000    lines_10ms = CAPTURE_FRAME_RATE * cap_maxlines / 10000 * 13 / 12;    if (0 == p_maxlines) {        p_maxlines = 1;    }    cap_exposure = ((p_exposure * CAPTURE_FRAME_RATE * cap_maxlines) /         (p_maxlines * PREVIEW_FRAME_RATE)) * 6 / 5;    //cap_exp_gain = 1126 * cap_exposure * cap_gain;    cap_exp_gain = cap_exposure * p_gain;  // in night mode, need multiply 2 again.    //cap_exp_gain >>= 9;    if (cap_exp_gain < (long)cap_maxlines * 16) {        cap_exposure = cap_exp_gain / 16;        if (cap_exposure > lines_10ms) {            cap_exposure /= lines_10ms;            cap_exposure *= lines_10ms;        }    } else {        cap_exposure = cap_maxlines;    }    if (0 == cap_exposure) {        cap_exposure = 1;    }    cap_gain = ((cap_exp_gain << 1) / cap_exposure + 1) >> 1;    exp_l = (cap_exposure << 4) & 0xFF;    exp_m = (cap_exposure >> 4) & 0xFF;    exp_h = (cap_exposure >> 12) & 0xFF;    INFO_GREEN("gain:0x%x, expl:0x%x, expm:0x%x, exph:0x%x, cap_maxlines:0x%x\n",         cap_gain, exp_l, exp_m, exp_h, cap_maxlines);        i2cc_set_reg(client, 0x350b, cap_gain);    i2cc_set_reg(client, 0x3502, exp_l);    i2cc_set_reg(client, 0x3501, exp_m);    i2cc_set_reg(client, 0x3500, exp_h);    /*    * add delay-time, to avoid boundary problem between dark and bright    */    mdelay(100);}static int ov5640_set_params(struct i2c_client *client, unsigned int *width,     unsigned int *height, enum v4l2_mbus_pixelcode code){    struct ov5640_priv *priv = to_ov5640(client);    int ret = -EINVAL;    int i;    const struct regval *reg_list = NULL;    int list_len = 0;    /* select format */    priv->cfmt = NULL;    for (i = 0; i < ARRAY_SIZE(ov5640_cfmts); i++) {        if (code == ov5640_cfmts[i].code) {            priv->cfmt = ov5640_cfmts + i;            break;        }    }    if (NULL == priv->cfmt) {        return (ret);    }    /* select win size, now only one, so select directly */    priv->win = select_win(*width, *height);    /* set hardware regs needed */    if (RESV_VGA == priv->win->resv) {        reset_ov5640(client);        /* set default regs */        write_regs(client, ov5640_init_regs, ARRAY_SIZE(ov5640_init_regs));        init_setting_values(priv);    }    switch (priv->win->resv) {        case RESV_XGA: {            reg_list = ov5640_qsxga_to_xga_regs;            list_len = ARRAY_SIZE(ov5640_qsxga_to_xga_regs);            break;        }        case RESV_SXGA: {            reg_list = ov5640_qsxga_to_sxga_regs;            list_len = ARRAY_SIZE(ov5640_qsxga_to_sxga_regs);            break;        }        case RESV_UXGA: {            reg_list = ov5640_qsxga_to_uxga_regs;            list_len = ARRAY_SIZE(ov5640_qsxga_to_uxga_regs);            break;        }        case RESV_QXGA: {            reg_list = ov5640_qsxga_to_qxga_regs;            list_len = ARRAY_SIZE(ov5640_qsxga_to_qxga_regs);            break;        }        case RESV_QSXGA:        default:            break;    }    if (RESV_VGA != priv->win->resv) {        unsigned int preview_exp;        unsigned short preview_maxl;        unsigned short preview_gain;        /* manually set exposure and gain */        i2cc_set_reg(client, 0x3503, 0x07);                get_preview_params(client, &preview_exp, &preview_maxl, &preview_gain);        write_regs(client, ov5640_qsxga_regs, ARRAY_SIZE(ov5640_qsxga_regs));        if (NULL != reg_list) {            write_regs(client, reg_list, list_len);        }        manual_set_exposure_and_gain(client, preview_exp, preview_maxl, preview_gain);            }    *width = priv->win->width;    *height = priv->win->height;    INFO_PURLPLE("ok, params are width:%d-height:%d\n", *width, *height);    return (0);}static int ov5640_g_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);    if (NULL == priv->win || NULL == priv->cfmt) {        unsigned int width = VGA_WIDTH;        unsigned int height = VGA_HEIGHT;        int ret = 0;        ret = ov5640_get_params(client, &width, &height,            V4L2_MBUS_FMT_YUYV8_2X8_BE);        if (ret < 0) {            return (ret);        }    }    vmf->width = priv->win->width;    vmf->height = priv->win->height;    vmf->code = priv->cfmt->code;    vmf->colorspace = priv->cfmt->colorspace;    vmf->field = V4L2_FIELD_NONE;    INFO_GREEN("ok, get fmt w:%dXh:%d-code:%d-csp:%d\n",         vmf->width, vmf->height, vmf->code, vmf->colorspace);    return (0);}static int ov5640_s_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);	int ret = ov5640_set_params(client, &vmf->width, &vmf->height,				    vmf->code);	if (!ret)		vmf->colorspace = priv->cfmt->colorspace;    INFO_PURLPLE("\n");	return (ret);}//  TODO..... modifystatic int ov5640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *vcc){	vcc->bounds.left = OV5640_COLUMN_SKIP;	vcc->bounds.top  = OV5640_ROW_SKIP;	vcc->bounds.width  = OV5640_MAX_WIDTH;	vcc->bounds.height = OV5640_MAX_HEIGHT;	vcc->defrect = vcc->bounds;  /* set default rect. */	vcc->type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;	vcc->pixelaspect.numerator   = 1;	vcc->pixelaspect.denominator = 1;    INFO_PURLPLE("\n");	return (0);}//  TODO..... modifystatic int ov5640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *vc){	vc->c.left	= 0;	vc->c.top	= 0;	vc->c.width	= QSXGA_WIDTH;	vc->c.height	= QSXGA_HEIGHT;	vc->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;    INFO_BLUE("\n");	return (0);}static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,			   enum v4l2_mbus_pixelcode *code){	if (index >= ARRAY_SIZE(ov5640_cfmts))		return -EINVAL;	*code = ov5640_cfmts[index].code;    OV_INFO("fmt index:%d\n", index);	return 0;}static int ov5640_set_brightness(struct i2c_client *client, int bright){    struct ov5640_priv *priv = to_ov5640(client);    unsigned char reg5587, reg5588;    if (bright < -4 || 4 < bright) {        OV_ERR("brightness - %d is out of range[-4, 4]\n", bright);        return (-ERANGE);    }    if (bright < 0) {        reg5587 = 0x10 * (-bright);        reg5588 = 0x09; /* bit[3] is Y bright sign */    } else {        reg5587 = 0x10 * bright;        reg5588 = 0x01;    }    i2cc_set_reg(client, 0x5001, 0xff);    i2cc_set_reg(client, 0x5587, reg5587);    i2cc_set_reg(client, 0x5580, 0x04);    i2cc_set_reg(client, 0x5588, reg5588);    priv->brightness = bright;    OV_INFO("brightness:%d, reg5587:0x%x, reg5588:0x%x\n",         bright, reg5587, reg5588);    return (0);}static int ov5640_set_contrast(struct i2c_client *client, int contrast){    struct ov5640_priv *priv = to_ov5640(client);    unsigned char y_gain, reg5588;    if (contrast < -4 || 4 < contrast) {        OV_ERR("contrast - %d is out of range[-4, 4]\n", contrast);        return (-ERANGE);    }    if (0 == contrast) {        reg5588 = 0x1;    } else {        reg5588 = 0x41;    }    y_gain = 0x20 + 0x4 * contrast;    i2cc_set_reg(client, 0x5001, 0xff);    i2cc_set_reg(client, 0x5580, 0x04);    i2cc_set_reg(client, 0x5586, y_gain);    i2cc_set_reg(client, 0x5585, y_gain);    i2cc_set_reg(client, 0x5588, reg5588);    priv->contrast = contrast;    OV_INFO("contrast:%d, y_gain:0x%x, reg5588:0x%x\n", contrast, y_gain, reg5588);    return (0);}/* auto, manual seperated is ok?? */static int ov5640_set_saturation(struct i2c_client *client, int saturation){    struct ov5640_priv *priv = to_ov5640(client);    unsigned char uv_max, uv_min, reg5588;    if (saturation < -4 || 4 < saturation) {        OV_ERR("saturation - %d is out of range[-4, 4]\n", saturation);        return (-ERANGE);    }    if (0 == saturation) {  /* different from application notes */        uv_max = 0x40;   /* max value for UV adjust */        uv_min = 0x10;   /* min value for UV adjust */        reg5588 = 0x01;  /* bit[6]==0, auto saturation */    } else {        uv_max = 0x40 + 0x10 * saturation; /* U sat. */        uv_min = uv_max; /* v sat */        reg5588 = 0x41;  /* bit[6]==1, manual saturation */    }    i2cc_set_reg(client, 0x5001, 0xff);  /* init is 0xa3 */    i2cc_set_reg(client, 0x5583, uv_max);    i2cc_set_reg(client, 0x5584, uv_min);    i2cc_set_reg(client, 0x5580, 0x02);  /* bit[1], enable(1)/disabe(0) saturation */    i2cc_set_reg(client, 0x5588, reg5588);     priv->saturation = saturation;    OV_INFO("saturation:%d\n", saturation);    return (0);}/* XXX:effect is reversed to note's picture exept -180. check it */static int ov5640_set_hue(struct i2c_client *client, int hue){    struct ov5640_priv *priv = to_ov5640(client);    unsigned char reg5581, reg5582, reg5588;    switch (hue) {        case -180:            reg5581 = 0x80;            reg5582 = 0x00;            reg5588 = 0x32;            break;        case -150:            reg5581 = 0x6f;            reg5582 = 0x40;            reg5588 = 0x32;            break;        case -120:            reg5581 = 0x40;            reg5582 = 0x6f;            reg5588 = 0x32;            break;        case -90:            reg5581 = 0x00;            reg5582 = 0x80;            reg5588 = 0x02;            break;        case -60:            reg5581 = 0x40;            reg5582 = 0x6f;            reg5588 = 0x02;            break;        case -30:            reg5581 = 0x6f;            reg5582 = 0x40;            reg5588 = 0x02;            break;        case 0:            reg5581 = 0x80;            reg5582 = 0x00;            reg5588 = 0x01;            break;        case 30:            reg5581 = 0x6f;            reg5582 = 0x40;            reg5588 = 0x01;            break;        case 60:            reg5581 = 0x40;            reg5582 = 0x6f;            reg5588 = 0x01;            break;        case 90:            reg5581 = 0x00;            reg5582 = 0x80;            reg5588 = 0x31;            break;        case 120:            reg5581 = 0x40;            reg5582 = 0x6f;            reg5588 = 0x31;            break;        case 150:            reg5581 = 0x6f;            reg5582 = 0x40;            reg5588 = 0x31;            break;        default:            OV_ERR("hue - %d is out of range[-180, 150]/step-30\n", hue);            return (-ERANGE);    }    i2cc_set_reg(client, 0x5001, 0xff);    i2cc_set_reg(client, 0x5580, 0x01);  /* XXXX:diff. from defualt value */    i2cc_set_reg(client, 0x5581, reg5581);  /* hue cos coefficient */    i2cc_set_reg(client, 0x5582, reg5582);  /* hue sin coefficient */    i2cc_set_reg(client, 0x5588, reg5588);    priv->hue = hue;    OV_INFO("hue: %d, 5581:0x%x, 5582:0x%x, 5588:0x%x\n",         hue, reg5581, reg5582, reg5588);    return (0);}/* default value here is different from init one. */static int ov5640_set_exposure_level(struct i2c_client *client, int level){    struct ov5640_priv *priv = to_ov5640(client);    unsigned char reg3a0f, reg3a10;    unsigned char reg3a1b, reg3a1e;    unsigned char reg3a11, reg3a1f;    reg3a0f = 0x38 + 0x8 * level;    reg3a10 = 0x30 + 0x8 * level;    reg3a1b = reg3a0f;    reg3a1e = reg3a10;    reg3a1f = 0x10;    switch (level) {        case -5:  /* -1.7EV */            reg3a11 = 0x20;            break;        case -4:  /* -1.3EV */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -