aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/i2c/ov7670.c
diff options
context:
space:
mode:
authorJavier Martin <javier.martin@vista-silicon.com>2013-01-29 07:12:13 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-08 14:23:32 -0200
commitd058e23704ad7e0b6876a94b0d8428dcef510b49 (patch)
tree0b8525ed274f5e11f631058a8bc5710d4a19324a /drivers/media/i2c/ov7670.c
parent06eae25f162e2a0d9e60f0ad3ec3d14c738fbe68 (diff)
[media] media: ov7670: add support for ov7675
ov7675 and ov7670 share the same registers but there is no way to distinguish them at runtime. However, they require different tweaks to achieve the desired resolution. For this reason this patch adds a new ov7675 entry to the ov7670_id table. Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Cc: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/ov7670.c')
-rw-r--r--drivers/media/i2c/ov7670.c101
1 files changed, 72 insertions, 29 deletions
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 882ddf6f66d3..51b198f79077 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -183,6 +183,27 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
#define REG_BD60MAX 0xab /* 60hz banding step limit */
+enum ov7670_model {
+ MODEL_OV7670 = 0,
+ MODEL_OV7675,
+};
+
+struct ov7670_win_size {
+ int width;
+ int height;
+ unsigned char com7_bit;
+ int hstart; /* Start/stop values for the camera. Note */
+ int hstop; /* that they do not always make complete */
+ int vstart; /* sense to humans, but evidently the sensor */
+ int vstop; /* will do the right thing... */
+ struct regval_list *regs; /* Regs to tweak */
+};
+
+struct ov7670_devtype {
+ /* formats supported for each model */
+ struct ov7670_win_size *win_sizes;
+ unsigned int n_win_sizes;
+};
/*
* Information we maintain about a known sensor.
@@ -198,6 +219,7 @@ struct ov7670_info {
int clock_speed; /* External clock speed (MHz) */
u8 clkrc; /* Clock divider value */
bool use_smbus; /* Use smbus I/O instead of I2C */
+ const struct ov7670_devtype *devtype; /* Device specifics */
};
static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
@@ -652,65 +674,70 @@ static struct regval_list ov7670_qcif_regs[] = {
{ 0xff, 0xff },
};
-static struct ov7670_win_size {
- int width;
- int height;
- unsigned char com7_bit;
- int hstart; /* Start/stop values for the camera. Note */
- int hstop; /* that they do not always make complete */
- int vstart; /* sense to humans, but evidently the sensor */
- int vstop; /* will do the right thing... */
- struct regval_list *regs; /* Regs to tweak */
-/* h/vref stuff */
-} ov7670_win_sizes[] = {
+static struct ov7670_win_size ov7670_win_sizes[] = {
/* VGA */
{
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
.com7_bit = COM7_FMT_VGA,
- .hstart = 158, /* These values from */
- .hstop = 14, /* Omnivision */
+ .hstart = 158, /* These values from */
+ .hstop = 14, /* Omnivision */
.vstart = 10,
.vstop = 490,
- .regs = NULL,
+ .regs = NULL,
},
/* CIF */
{
.width = CIF_WIDTH,
.height = CIF_HEIGHT,
.com7_bit = COM7_FMT_CIF,
- .hstart = 170, /* Empirically determined */
+ .hstart = 170, /* Empirically determined */
.hstop = 90,
.vstart = 14,
.vstop = 494,
- .regs = NULL,
+ .regs = NULL,
},
/* QVGA */
{
.width = QVGA_WIDTH,
.height = QVGA_HEIGHT,
.com7_bit = COM7_FMT_QVGA,
- .hstart = 168, /* Empirically determined */
+ .hstart = 168, /* Empirically determined */
.hstop = 24,
.vstart = 12,
.vstop = 492,
- .regs = NULL,
+ .regs = NULL,
},
/* QCIF */
{
.width = QCIF_WIDTH,
.height = QCIF_HEIGHT,
.com7_bit = COM7_FMT_VGA, /* see comment above */
- .hstart = 456, /* Empirically determined */
+ .hstart = 456, /* Empirically determined */
.hstop = 24,
.vstart = 14,
.vstop = 494,
- .regs = ov7670_qcif_regs,
- },
+ .regs = ov7670_qcif_regs,
+ }
};
-#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
-
+static struct ov7670_win_size ov7675_win_sizes[] = {
+ /*
+ * Currently, only VGA is supported. Theoretically it could be possible
+ * to support CIF, QVGA and QCIF too. Taking values for ov7670 as a
+ * base and tweak them empirically could be required.
+ */
+ {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .com7_bit = COM7_FMT_VGA,
+ .hstart = 158, /* These values from */
+ .hstop = 14, /* Omnivision */
+ .vstart = 14, /* Empirically determined */
+ .vstop = 494,
+ .regs = NULL,
+ }
+};
/*
* Store a set of start/stop values into the camera.
@@ -761,6 +788,8 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
{
int index;
struct ov7670_win_size *wsize;
+ struct ov7670_info *info = to_state(sd);
+ unsigned int n_win_sizes = info->devtype->n_win_sizes;
for (index = 0; index < N_OV7670_FMTS; index++)
if (ov7670_formats[index].mbus_code == fmt->code)
@@ -780,11 +809,11 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
* Round requested image size down to the nearest
* we support, but not below the smallest.
*/
- for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
- wsize++)
+ for (wsize = info->devtype->win_sizes;
+ wsize < info->devtype->win_sizes + n_win_sizes; wsize++)
if (fmt->width >= wsize->width && fmt->height >= wsize->height)
break;
- if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
+ if (wsize >= info->devtype->win_sizes + n_win_sizes)
wsize--; /* Take the smallest one */
if (ret_wsize != NULL)
*ret_wsize = wsize;
@@ -931,13 +960,14 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
int i;
int num_valid = -1;
__u32 index = fsize->index;
+ unsigned int n_win_sizes = info->devtype->n_win_sizes;
/*
* If a minimum width/height was requested, filter out the capture
* windows that fall outside that.
*/
- for (i = 0; i < N_WIN_SIZES; i++) {
- struct ov7670_win_size *win = &ov7670_win_sizes[index];
+ for (i = 0; i < n_win_sizes; i++) {
+ struct ov7670_win_size *win = &info->devtype->win_sizes[index];
if (info->min_width && win->width < info->min_width)
continue;
if (info->min_height && win->height < info->min_height)
@@ -1510,6 +1540,17 @@ static const struct v4l2_subdev_ops ov7670_ops = {
/* ----------------------------------------------------------------------- */
+static const struct ov7670_devtype ov7670_devdata[] = {
+ [MODEL_OV7670] = {
+ .win_sizes = ov7670_win_sizes,
+ .n_win_sizes = ARRAY_SIZE(ov7670_win_sizes),
+ },
+ [MODEL_OV7675] = {
+ .win_sizes = ov7675_win_sizes,
+ .n_win_sizes = ARRAY_SIZE(ov7675_win_sizes),
+ },
+};
+
static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1551,6 +1592,7 @@ static int ov7670_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
+ info->devtype = &ov7670_devdata[id->driver_data];
info->fmt = &ov7670_formats[0];
info->sat = 128; /* Review this */
info->clkrc = info->clock_speed / 30;
@@ -1568,7 +1610,8 @@ static int ov7670_remove(struct i2c_client *client)
}
static const struct i2c_device_id ov7670_id[] = {
- { "ov7670", 0 },
+ { "ov7670", MODEL_OV7670 },
+ { "ov7675", MODEL_OV7675 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ov7670_id);