Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 357523
b: refs/heads/master
c: f6dd927
h: refs/heads/master
i:
  357521: 5249b81
  357519: c440f7b
v: v3
  • Loading branch information
Javier Martin authored and Mauro Carvalho Chehab committed Feb 8, 2013
1 parent 3d8f76e commit e343a23
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f748cd3ec8039a01d260ba0d51687afdf93c6e67
refs/heads/master: f6dd927f34d64014c4b196132b5cdf9f2e2a3ae5
136 changes: 118 additions & 18 deletions trunk/drivers/media/i2c/ov7670.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
*/
#define OV7670_I2C_ADDR 0x42

#define PLL_FACTOR 4

/* Registers */
#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
#define REG_BLUE 0x01 /* blue gain */
Expand Down Expand Up @@ -164,6 +166,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");

#define REG_GFIX 0x69 /* Fix gain control */

#define REG_DBLV 0x6b /* PLL control an debugging */
#define DBLV_BYPASS 0x00 /* Bypass PLL */
#define DBLV_X4 0x01 /* clock x4 */
#define DBLV_X6 0x10 /* clock x6 */
#define DBLV_X8 0x11 /* clock x8 */

#define REG_REG76 0x76 /* OV's name */
#define R76_BLKPCOR 0x80 /* Black pixel correction enable */
#define R76_WHTPCOR 0x40 /* White pixel correction enable */
Expand Down Expand Up @@ -203,6 +211,9 @@ struct ov7670_devtype {
/* formats supported for each model */
struct ov7670_win_size *win_sizes;
unsigned int n_win_sizes;
/* callbacks for frame rate control */
int (*set_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
void (*get_framerate)(struct v4l2_subdev *, struct v4l2_fract *);
};

/*
Expand Down Expand Up @@ -739,6 +750,98 @@ static struct ov7670_win_size ov7675_win_sizes[] = {
}
};

static void ov7675_get_framerate(struct v4l2_subdev *sd,
struct v4l2_fract *tpf)
{
struct ov7670_info *info = to_state(sd);
u32 clkrc = info->clkrc;
u32 pll_factor = PLL_FACTOR;

clkrc++;
if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
clkrc = (clkrc >> 1);

tpf->numerator = 1;
tpf->denominator = (5 * pll_factor * info->clock_speed) /
(4 * clkrc);
}

static int ov7675_set_framerate(struct v4l2_subdev *sd,
struct v4l2_fract *tpf)
{
struct ov7670_info *info = to_state(sd);
u32 clkrc;
u32 pll_factor = PLL_FACTOR;
int ret;

/*
* The formula is fps = 5/4*pixclk for YUV/RGB and
* fps = 5/2*pixclk for RAW.
*
* pixclk = clock_speed / (clkrc + 1) * PLLfactor
*
*/
if (tpf->numerator == 0 || tpf->denominator == 0) {
clkrc = 0;
} else {
clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
(4 * tpf->denominator);
if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
clkrc = (clkrc << 1);
clkrc--;
}

/*
* The datasheet claims that clkrc = 0 will divide the input clock by 1
* but we've checked with an oscilloscope that it divides by 2 instead.
* So, if clkrc = 0 just bypass the divider.
*/
if (clkrc <= 0)
clkrc = CLK_EXT;
else if (clkrc > CLK_SCALE)
clkrc = CLK_SCALE;
info->clkrc = clkrc;

/* Recalculate frame rate */
ov7675_get_framerate(sd, tpf);

ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
if (ret < 0)
return ret;
return ov7670_write(sd, REG_DBLV, DBLV_X4);
}

static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd,
struct v4l2_fract *tpf)
{
struct ov7670_info *info = to_state(sd);

tpf->numerator = 1;
tpf->denominator = info->clock_speed;
if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
tpf->denominator /= (info->clkrc & CLK_SCALE);
}

static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd,
struct v4l2_fract *tpf)
{
struct ov7670_info *info = to_state(sd);
int div;

if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1; /* Reset to full rate */
else
div = (tpf->numerator * info->clock_speed) / tpf->denominator;
if (div == 0)
div = 1;
else if (div > CLK_SCALE)
div = CLK_SCALE;
info->clkrc = (info->clkrc & 0x80) | div;
tpf->numerator = 1;
tpf->denominator = info->clock_speed / div;
return ov7670_write(sd, REG_CLKRC, info->clkrc);
}

/*
* Store a set of start/stop values into the camera.
*/
Expand Down Expand Up @@ -913,10 +1016,8 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)

memset(cp, 0, sizeof(struct v4l2_captureparm));
cp->capability = V4L2_CAP_TIMEPERFRAME;
cp->timeperframe.numerator = 1;
cp->timeperframe.denominator = info->clock_speed;
if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
info->devtype->get_framerate(sd, &cp->timeperframe);

return 0;
}

Expand All @@ -925,25 +1026,13 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
struct v4l2_captureparm *cp = &parms->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe;
struct ov7670_info *info = to_state(sd);
int div;

if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (cp->extendedmode != 0)
return -EINVAL;

if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1; /* Reset to full rate */
else
div = (tpf->numerator * info->clock_speed) / tpf->denominator;
if (div == 0)
div = 1;
else if (div > CLK_SCALE)
div = CLK_SCALE;
info->clkrc = (info->clkrc & 0x80) | div;
tpf->numerator = 1;
tpf->denominator = info->clock_speed / div;
return ov7670_write(sd, REG_CLKRC, info->clkrc);
return info->devtype->set_framerate(sd, tpf);
}


Expand Down Expand Up @@ -1560,16 +1649,21 @@ static const struct ov7670_devtype ov7670_devdata[] = {
[MODEL_OV7670] = {
.win_sizes = ov7670_win_sizes,
.n_win_sizes = ARRAY_SIZE(ov7670_win_sizes),
.set_framerate = ov7670_set_framerate_legacy,
.get_framerate = ov7670_get_framerate_legacy,
},
[MODEL_OV7675] = {
.win_sizes = ov7675_win_sizes,
.n_win_sizes = ARRAY_SIZE(ov7675_win_sizes),
.set_framerate = ov7675_set_framerate,
.get_framerate = ov7675_get_framerate,
},
};

static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct v4l2_fract tpf;
struct v4l2_subdev *sd;
struct ov7670_info *info;
int ret;
Expand Down Expand Up @@ -1611,7 +1705,13 @@ static int ov7670_probe(struct i2c_client *client,
info->devtype = &ov7670_devdata[id->driver_data];
info->fmt = &ov7670_formats[0];
info->sat = 128; /* Review this */
info->clkrc = info->clock_speed / 30;
info->clkrc = 0;

/* Set default frame rate to 30 fps */
tpf.numerator = 1;
tpf.denominator = 30;
info->devtype->set_framerate(sd, &tpf);

return 0;
}

Expand Down

0 comments on commit e343a23

Please sign in to comment.