Commit 14386c2b authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (11113): ov7670: convert to v4l2_subdev

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Acked-by: default avatarJonathan Corbet <corbet@lwn.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2da9479a
...@@ -12,18 +12,22 @@ ...@@ -12,18 +12,22 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/i2c.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/v4l2-common.h> #include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h> #include <media/v4l2-chip-ident.h>
#include <linux/i2c.h> #include <media/v4l2-i2c-drv-legacy.h>
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
/* /*
* Basic window sizes. These probably belong somewhere more globally * Basic window sizes. These probably belong somewhere more globally
* useful. * useful.
...@@ -189,11 +193,16 @@ MODULE_LICENSE("GPL"); ...@@ -189,11 +193,16 @@ MODULE_LICENSE("GPL");
*/ */
struct ov7670_format_struct; /* coming later */ struct ov7670_format_struct; /* coming later */
struct ov7670_info { struct ov7670_info {
struct v4l2_subdev sd;
struct ov7670_format_struct *fmt; /* Current format */ struct ov7670_format_struct *fmt; /* Current format */
unsigned char sat; /* Saturation value */ unsigned char sat; /* Saturation value */
int hue; /* Hue value */ int hue; /* Hue value */
}; };
static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
{
return container_of(sd, struct ov7670_info, sd);
}
...@@ -400,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = { ...@@ -400,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = {
* Low-level register I/O. * Low-level register I/O.
*/ */
static int ov7670_read(struct i2c_client *c, unsigned char reg, static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
unsigned char *value) unsigned char *value)
{ {
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret; int ret;
ret = i2c_smbus_read_byte_data(c, reg); ret = i2c_smbus_read_byte_data(client, reg);
if (ret >= 0) { if (ret >= 0) {
*value = (unsigned char) ret; *value = (unsigned char)ret;
ret = 0; ret = 0;
} }
return ret; return ret;
} }
static int ov7670_write(struct i2c_client *c, unsigned char reg, static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
unsigned char value) unsigned char value)
{ {
int ret = i2c_smbus_write_byte_data(c, reg, value); struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = i2c_smbus_write_byte_data(client, reg, value);
if (reg == REG_COM7 && (value & COM7_RESET)) if (reg == REG_COM7 && (value & COM7_RESET))
msleep(2); /* Wait for reset to run */ msleep(2); /* Wait for reset to run */
return ret; return ret;
...@@ -427,10 +439,10 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg, ...@@ -427,10 +439,10 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg,
/* /*
* Write a list of register settings; ff/ff stops the process. * Write a list of register settings; ff/ff stops the process.
*/ */
static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals)
{ {
while (vals->reg_num != 0xff || vals->value != 0xff) { while (vals->reg_num != 0xff || vals->value != 0xff) {
int ret = ov7670_write(c, vals->reg_num, vals->value); int ret = ov7670_write(sd, vals->reg_num, vals->value);
if (ret < 0) if (ret < 0)
return ret; return ret;
vals++; vals++;
...@@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) ...@@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
/* /*
* Stuff that knows about the sensor. * Stuff that knows about the sensor.
*/ */
static void ov7670_reset(struct i2c_client *client) static int ov7670_reset(struct v4l2_subdev *sd, u32 val)
{ {
ov7670_write(client, REG_COM7, COM7_RESET); ov7670_write(sd, REG_COM7, COM7_RESET);
msleep(1); msleep(1);
return 0;
} }
static int ov7670_init(struct i2c_client *client) static int ov7670_init(struct v4l2_subdev *sd, u32 val)
{ {
return ov7670_write_array(client, ov7670_default_regs); return ov7670_write_array(sd, ov7670_default_regs);
} }
static int ov7670_detect(struct i2c_client *client) static int ov7670_detect(struct v4l2_subdev *sd)
{ {
unsigned char v; unsigned char v;
int ret; int ret;
ret = ov7670_init(client); ret = ov7670_init(sd, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = ov7670_read(client, REG_MIDH, &v); ret = ov7670_read(sd, REG_MIDH, &v);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (v != 0x7f) /* OV manuf. id. */ if (v != 0x7f) /* OV manuf. id. */
return -ENODEV; return -ENODEV;
ret = ov7670_read(client, REG_MIDL, &v); ret = ov7670_read(sd, REG_MIDL, &v);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (v != 0xa2) if (v != 0xa2)
...@@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client) ...@@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client)
/* /*
* OK, we know we have an OmniVision chip...but which one? * OK, we know we have an OmniVision chip...but which one?
*/ */
ret = ov7670_read(client, REG_PID, &v); ret = ov7670_read(sd, REG_PID, &v);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ if (v != 0x76) /* PID + VER = 0x76 / 0x73 */
return -ENODEV; return -ENODEV;
ret = ov7670_read(client, REG_VER, &v); ret = ov7670_read(sd, REG_VER, &v);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ if (v != 0x73) /* PID + VER = 0x76 / 0x73 */
...@@ -627,7 +640,7 @@ static struct ov7670_win_size { ...@@ -627,7 +640,7 @@ static struct ov7670_win_size {
/* /*
* Store a set of start/stop values into the camera. * Store a set of start/stop values into the camera.
*/ */
static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
int vstart, int vstop) int vstart, int vstop)
{ {
int ret; int ret;
...@@ -637,26 +650,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, ...@@ -637,26 +650,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,
* hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
* a mystery "edge offset" value in the top two bits of href. * a mystery "edge offset" value in the top two bits of href.
*/ */
ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
ret += ov7670_read(client, REG_HREF, &v); ret += ov7670_read(sd, REG_HREF, &v);
v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
msleep(10); msleep(10);
ret += ov7670_write(client, REG_HREF, v); ret += ov7670_write(sd, REG_HREF, v);
/* /*
* Vertical: similar arrangement, but only 10 bits. * Vertical: similar arrangement, but only 10 bits.
*/ */
ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
ret += ov7670_read(client, REG_VREF, &v); ret += ov7670_read(sd, REG_VREF, &v);
v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
msleep(10); msleep(10);
ret += ov7670_write(client, REG_VREF, v); ret += ov7670_write(sd, REG_VREF, v);
return ret; return ret;
} }
static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{ {
struct ov7670_format_struct *ofmt; struct ov7670_format_struct *ofmt;
...@@ -671,7 +684,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) ...@@ -671,7 +684,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt)
} }
static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
struct v4l2_format *fmt,
struct ov7670_format_struct **ret_fmt, struct ov7670_format_struct **ret_fmt,
struct ov7670_win_size **ret_wsize) struct ov7670_win_size **ret_wsize)
{ {
...@@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, ...@@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
return 0; return 0;
} }
static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{
return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
}
/* /*
* Set a format. * Set a format.
*/ */
static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
{ {
int ret; int ret;
struct ov7670_format_struct *ovfmt; struct ov7670_format_struct *ovfmt;
struct ov7670_win_size *wsize; struct ov7670_win_size *wsize;
struct ov7670_info *info = i2c_get_clientdata(c); struct ov7670_info *info = to_state(sd);
unsigned char com7, clkrc; unsigned char com7, clkrc = 0;
ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
if (ret) if (ret)
return ret; return ret;
/* /*
...@@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) ...@@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
* the colors. * the colors.
*/ */
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
ret = ov7670_read(c, REG_CLKRC, &clkrc); ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) ...@@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
*/ */
com7 = ovfmt->regs[0].value; com7 = ovfmt->regs[0].value;
com7 |= wsize->com7_bit; com7 |= wsize->com7_bit;
ov7670_write(c, REG_COM7, com7); ov7670_write(sd, REG_COM7, com7);
/* /*
* Now write the rest of the array. Also store start/stops * Now write the rest of the array. Also store start/stops
*/ */
ov7670_write_array(c, ovfmt->regs + 1); ov7670_write_array(sd, ovfmt->regs + 1);
ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
wsize->vstop); wsize->vstop);
ret = 0; ret = 0;
if (wsize->regs) if (wsize->regs)
ret = ov7670_write_array(c, wsize->regs); ret = ov7670_write_array(sd, wsize->regs);
info->fmt = ovfmt; info->fmt = ovfmt;
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)
ret = ov7670_write(c, REG_CLKRC, clkrc); ret = ov7670_write(sd, REG_CLKRC, clkrc);
return ret; return ret;
} }
...@@ -768,7 +787,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) ...@@ -768,7 +787,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
* Implement G/S_PARM. There is a "high quality" mode we could try * Implement G/S_PARM. There is a "high quality" mode we could try
* to do someday; for now, we just do the frame rate tweak. * to do someday; for now, we just do the frame rate tweak.
*/ */
static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{ {
struct v4l2_captureparm *cp = &parms->parm.capture; struct v4l2_captureparm *cp = &parms->parm.capture;
unsigned char clkrc; unsigned char clkrc;
...@@ -776,7 +795,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) ...@@ -776,7 +795,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
ret = ov7670_read(c, REG_CLKRC, &clkrc); ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0) if (ret < 0)
return ret; return ret;
memset(cp, 0, sizeof(struct v4l2_captureparm)); memset(cp, 0, sizeof(struct v4l2_captureparm));
...@@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) ...@@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
return 0; return 0;
} }
static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{ {
struct v4l2_captureparm *cp = &parms->parm.capture; struct v4l2_captureparm *cp = &parms->parm.capture;
struct v4l2_fract *tpf = &cp->timeperframe; struct v4l2_fract *tpf = &cp->timeperframe;
...@@ -802,7 +821,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) ...@@ -802,7 +821,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
/* /*
* CLKRC has a reserved bit, so let's preserve it. * CLKRC has a reserved bit, so let's preserve it.
*/ */
ret = ov7670_read(c, REG_CLKRC, &clkrc); ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (tpf->numerator == 0 || tpf->denominator == 0) if (tpf->numerator == 0 || tpf->denominator == 0)
...@@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) ...@@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
clkrc = (clkrc & 0x80) | div; clkrc = (clkrc & 0x80) | div;
tpf->numerator = 1; tpf->numerator = 1;
tpf->denominator = OV7670_FRAME_RATE/div; tpf->denominator = OV7670_FRAME_RATE/div;
return ov7670_write(c, REG_CLKRC, clkrc); return ov7670_write(sd, REG_CLKRC, clkrc);
} }
...@@ -829,7 +848,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) ...@@ -829,7 +848,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
static int ov7670_store_cmatrix(struct i2c_client *client, static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
int matrix[CMATRIX_LEN]) int matrix[CMATRIX_LEN])
{ {
int i, ret; int i, ret;
...@@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client, ...@@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
* Weird crap seems to exist in the upper part of * Weird crap seems to exist in the upper part of
* the sign bits register, so let's preserve it. * the sign bits register, so let's preserve it.
*/ */
ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits);
signbits &= 0xc0; signbits &= 0xc0;
for (i = 0; i < CMATRIX_LEN; i++) { for (i = 0; i < CMATRIX_LEN; i++) {
...@@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client, ...@@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
else else
raw = matrix[i] & 0xff; raw = matrix[i] & 0xff;
} }
ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw);
} }
ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits);
return ret; return ret;
} }
...@@ -943,29 +962,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info, ...@@ -943,29 +962,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
static int ov7670_t_sat(struct i2c_client *client, int value) static int ov7670_t_sat(struct v4l2_subdev *sd, int value)
{ {
struct ov7670_info *info = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd);
int matrix[CMATRIX_LEN]; int matrix[CMATRIX_LEN];
int ret; int ret;
info->sat = value; info->sat = value;
ov7670_calc_cmatrix(info, matrix); ov7670_calc_cmatrix(info, matrix);
ret = ov7670_store_cmatrix(client, matrix); ret = ov7670_store_cmatrix(sd, matrix);
return ret; return ret;
} }
static int ov7670_q_sat(struct i2c_client *client, __s32 *value) static int ov7670_q_sat(struct v4l2_subdev *sd, __s32 *value)
{ {
struct ov7670_info *info = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd);
*value = info->sat; *value = info->sat;
return 0; return 0;
} }
static int ov7670_t_hue(struct i2c_client *client, int value) static int ov7670_t_hue(struct v4l2_subdev *sd, int value)
{ {
struct ov7670_info *info = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd);
int matrix[CMATRIX_LEN]; int matrix[CMATRIX_LEN];
int ret; int ret;
...@@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value) ...@@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value)
return -EINVAL; return -EINVAL;
info->hue = value; info->hue = value;
ov7670_calc_cmatrix(info, matrix); ov7670_calc_cmatrix(info, matrix);
ret = ov7670_store_cmatrix(client, matrix); ret = ov7670_store_cmatrix(sd, matrix);
return ret; return ret;
} }
static int ov7670_q_hue(struct i2c_client *client, __s32 *value) static int ov7670_q_hue(struct v4l2_subdev *sd, __s32 *value)
{ {
struct ov7670_info *info = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd);
*value = info->hue; *value = info->hue;
return 0; return 0;
...@@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v) ...@@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v)
{ {
if ((v & 0x80) == 0) if ((v & 0x80) == 0)
return v + 128; return v + 128;
else return 128 - (v & 0x7f);
return 128 - (v & 0x7f);
} }
...@@ -1003,105 +1021,104 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) ...@@ -1003,105 +1021,104 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
{ {
if (v > 127) if (v > 127)
return v & 0x7f; return v & 0x7f;
else return (128 - v) | 0x80;
return (128 - v) | 0x80;
} }
static int ov7670_t_brightness(struct i2c_client *client, int value) static int ov7670_t_brightness(struct v4l2_subdev *sd, int value)
{ {
unsigned char com8 = 0, v; unsigned char com8 = 0, v;
int ret; int ret;
ov7670_read(client, REG_COM8, &com8); ov7670_read(sd, REG_COM8, &com8);
com8 &= ~COM8_AEC; com8 &= ~COM8_AEC;
ov7670_write(client, REG_COM8, com8); ov7670_write(sd, REG_COM8, com8);
v = ov7670_abs_to_sm(value); v = ov7670_abs_to_sm(value);
ret = ov7670_write(client, REG_BRIGHT, v); ret = ov7670_write(sd, REG_BRIGHT, v);
return ret; return ret;
} }
static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) static int ov7670_q_brightness(struct v4l2_subdev *sd, __s32 *value)
{ {
unsigned char v = 0; unsigned char v = 0;
int ret = ov7670_read(client, REG_BRIGHT, &v); int ret = ov7670_read(sd, REG_BRIGHT, &v);
*value = ov7670_sm_to_abs(v); *value = ov7670_sm_to_abs(v);
return ret; return ret;
} }
static int ov7670_t_contrast(struct i2c_client *client, int value) static int ov7670_t_contrast(struct v4l2_subdev *sd, int value)
{ {
return ov7670_write(client, REG_CONTRAS, (unsigned char) value); return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
} }
static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) static int ov7670_q_contrast(struct v4l2_subdev *sd, __s32 *value)
{ {
unsigned char v = 0; unsigned char v = 0;
int ret = ov7670_read(client, REG_CONTRAS, &v); int ret = ov7670_read(sd, REG_CONTRAS, &v);
*value = v; *value = v;
return ret; return ret;
} }
static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) static int ov7670_q_hflip(struct v4l2_subdev *sd, __s32 *value)
{ {
int ret; int ret;
unsigned char v = 0; unsigned char v = 0;
ret = ov7670_read(client, REG_MVFP, &v); ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_MIRROR) == MVFP_MIRROR; *value = (v & MVFP_MIRROR) == MVFP_MIRROR;
return ret; return ret;
} }
static int ov7670_t_hflip(struct i2c_client *client, int value) static int ov7670_t_hflip(struct v4l2_subdev *sd, int value)
{ {
unsigned char v = 0; unsigned char v = 0;
int ret; int ret;
ret = ov7670_read(client, REG_MVFP, &v); ret = ov7670_read(sd, REG_MVFP, &v);
if (value) if (value)
v |= MVFP_MIRROR; v |= MVFP_MIRROR;
else else
v &= ~MVFP_MIRROR; v &= ~MVFP_MIRROR;
msleep(10); /* FIXME */ msleep(10); /* FIXME */
ret += ov7670_write(client, REG_MVFP, v); ret += ov7670_write(sd, REG_MVFP, v);
return ret; return ret;
} }
static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) static int ov7670_q_vflip(struct v4l2_subdev *sd, __s32 *value)
{ {
int ret; int ret;
unsigned char v = 0; unsigned char v = 0;
ret = ov7670_read(client, REG_MVFP, &v); ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_FLIP) == MVFP_FLIP; *value = (v & MVFP_FLIP) == MVFP_FLIP;
return ret; return ret;
} }
static int ov7670_t_vflip(struct i2c_client *client, int value) static int ov7670_t_vflip(struct v4l2_subdev *sd, int value)
{ {
unsigned char v = 0; unsigned char v = 0;
int ret; int ret;
ret = ov7670_read(client, REG_MVFP, &v); ret = ov7670_read(sd, REG_MVFP, &v);
if (value) if (value)
v |= MVFP_FLIP; v |= MVFP_FLIP;
else else
v &= ~MVFP_FLIP; v &= ~MVFP_FLIP;
msleep(10); /* FIXME */ msleep(10); /* FIXME */
ret += ov7670_write(client, REG_MVFP, v); ret += ov7670_write(sd, REG_MVFP, v);
return ret; return ret;
} }
static struct ov7670_control { static struct ov7670_control {
struct v4l2_queryctrl qc; struct v4l2_queryctrl qc;
int (*query)(struct i2c_client *c, __s32 *value); int (*query)(struct v4l2_subdev *sd, __s32 *value);
int (*tweak)(struct i2c_client *c, int value); int (*tweak)(struct v4l2_subdev *sd, int value);
} ov7670_controls[] = } ov7670_controls[] =
{ {
{ {
...@@ -1200,7 +1217,7 @@ static struct ov7670_control *ov7670_find_control(__u32 id) ...@@ -1200,7 +1217,7 @@ static struct ov7670_control *ov7670_find_control(__u32 id)
} }
static int ov7670_queryctrl(struct i2c_client *client, static int ov7670_queryctrl(struct v4l2_subdev *sd,
struct v4l2_queryctrl *qc) struct v4l2_queryctrl *qc)
{ {
struct ov7670_control *ctrl = ov7670_find_control(qc->id); struct ov7670_control *ctrl = ov7670_find_control(qc->id);
...@@ -1211,161 +1228,128 @@ static int ov7670_queryctrl(struct i2c_client *client, ...@@ -1211,161 +1228,128 @@ static int ov7670_queryctrl(struct i2c_client *client,
return 0; return 0;
} }
static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{ {
struct ov7670_control *octrl = ov7670_find_control(ctrl->id); struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
int ret; int ret;
if (octrl == NULL) if (octrl == NULL)
return -EINVAL; return -EINVAL;
ret = octrl->query(client, &ctrl->value); ret = octrl->query(sd, &ctrl->value);
if (ret >= 0) if (ret >= 0)
return 0; return 0;
return ret; return ret;
} }
static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{ {
struct ov7670_control *octrl = ov7670_find_control(ctrl->id); struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
int ret; int ret;
if (octrl == NULL) if (octrl == NULL)
return -EINVAL; return -EINVAL;
ret = octrl->tweak(client, ctrl->value); ret = octrl->tweak(sd, ctrl->value);
if (ret >= 0) if (ret >= 0)
return 0; return 0;
return ret; return ret;
} }
static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
}
static int ov7670_command(struct i2c_client *client, unsigned cmd, void *arg)
{
return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
.g_chip_ident = ov7670_g_chip_ident,
.g_ctrl = ov7670_g_ctrl,
.s_ctrl = ov7670_s_ctrl,
.queryctrl = ov7670_queryctrl,
.reset = ov7670_reset,
.init = ov7670_init,
};
static const struct v4l2_subdev_video_ops ov7670_video_ops = {
.enum_fmt = ov7670_enum_fmt,
.try_fmt = ov7670_try_fmt,
.s_fmt = ov7670_s_fmt,
.s_parm = ov7670_s_parm,
.g_parm = ov7670_g_parm,
};
static const struct v4l2_subdev_ops ov7670_ops = {
.core = &ov7670_core_ops,
.video = &ov7670_video_ops,
};
/* /* ----------------------------------------------------------------------- */
* Basic i2c stuff.
*/
static struct i2c_driver ov7670_driver;
static int ov7670_attach(struct i2c_adapter *adapter) static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{ {
int ret; struct v4l2_subdev *sd;
struct i2c_client *client;
struct ov7670_info *info; struct ov7670_info *info;
int ret;
/* /*
* For now: only deal with adapters we recognize. * For now: only deal with adapters we recognize.
*/ */
if (adapter->id != I2C_HW_SMBUS_CAFE) if (client->adapter->id != I2C_HW_SMBUS_CAFE)
return -ENODEV; return -ENODEV;
info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); if (info == NULL)
if (! client)
return -ENOMEM; return -ENOMEM;
client->adapter = adapter; sd = &info->sd;
client->addr = OV7670_I2C_ADDR; v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
client->driver = &ov7670_driver,
strcpy(client->name, "OV7670"); /* Make sure it's an ov7670 */
/* ret = ov7670_detect(sd);
* Set up our info structure. if (ret) {
*/ v4l_dbg(1, debug, client,
info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
if (! info) { client->addr << 1, client->adapter->name);
ret = -ENOMEM; kfree(info);
goto out_free; return ret;
} }
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
info->fmt = &ov7670_formats[0]; info->fmt = &ov7670_formats[0];
info->sat = 128; /* Review this */ info->sat = 128; /* Review this */
i2c_set_clientdata(client, info);
/*
* Make sure it's an ov7670
*/
ret = ov7670_detect(client);
if (ret)
goto out_free_info;
ret = i2c_attach_client(client);
if (ret)
goto out_free_info;
return 0; return 0;
out_free_info:
kfree(info);
out_free:
kfree(client);
return ret;
} }
static int ov7670_detach(struct i2c_client *client) static int ov7670_remove(struct i2c_client *client)
{ {
i2c_detach_client(client); struct v4l2_subdev *sd = i2c_get_clientdata(client);
kfree(i2c_get_clientdata(client));
kfree(client);
return 0;
}
v4l2_device_unregister_subdev(sd);
static int ov7670_command(struct i2c_client *client, unsigned int cmd, kfree(to_state(sd));
void *arg) return 0;
{
switch (cmd) {
case VIDIOC_DBG_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
case VIDIOC_INT_RESET:
ov7670_reset(client);
return 0;
case VIDIOC_INT_INIT:
return ov7670_init(client);
case VIDIOC_ENUM_FMT:
return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg);
case VIDIOC_TRY_FMT:
return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL);
case VIDIOC_S_FMT:
return ov7670_s_fmt(client, (struct v4l2_format *) arg);
case VIDIOC_QUERYCTRL:
return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg);
case VIDIOC_S_CTRL:
return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
case VIDIOC_G_CTRL:
return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
case VIDIOC_S_PARM:
return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
case VIDIOC_G_PARM:
return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
}
return -EINVAL;
} }
static const struct i2c_device_id ov7670_id[] = {
{ "ov7670", 0 },
static struct i2c_driver ov7670_driver = { { }
.driver = { };
.name = "ov7670", MODULE_DEVICE_TABLE(i2c, ov7670_id);
},
.id = I2C_DRIVERID_OV7670, static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.attach_adapter = ov7670_attach, .name = "ov7670",
.detach_client = ov7670_detach, .command = ov7670_command,
.command = ov7670_command, .probe = ov7670_probe,
.remove = ov7670_remove,
.legacy_class = I2C_CLASS_TV_ANALOG,
.id_table = ov7670_id,
}; };
/*
* Module initialization
*/
static int __init ov7670_mod_init(void)
{
printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n");
return i2c_add_driver(&ov7670_driver);
}
static void __exit ov7670_mod_exit(void)
{
i2c_del_driver(&ov7670_driver);
}
module_init(ov7670_mod_init);
module_exit(ov7670_mod_exit);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment