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

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Acked-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Hans Verkuil 2009-03-18 13:01:06 -03:00 committed by Mauro Carvalho Chehab
parent 2da9479aaa
commit 14386c2b77

View File

@ -12,18 +12,22 @@
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.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_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
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
* useful.
@ -189,11 +193,16 @@ MODULE_LICENSE("GPL");
*/
struct ov7670_format_struct; /* coming later */
struct ov7670_info {
struct v4l2_subdev sd;
struct ov7670_format_struct *fmt; /* Current format */
unsigned char sat; /* Saturation 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[] = {
* 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)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
ret = i2c_smbus_read_byte_data(c, reg);
ret = i2c_smbus_read_byte_data(client, reg);
if (ret >= 0) {
*value = (unsigned char) ret;
*value = (unsigned char)ret;
ret = 0;
}
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)
{
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))
msleep(2); /* Wait for reset to run */
return ret;
@ -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.
*/
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) {
int ret = ov7670_write(c, vals->reg_num, vals->value);
int ret = ov7670_write(sd, vals->reg_num, vals->value);
if (ret < 0)
return ret;
vals++;
@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals)
/*
* 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);
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;
int ret;
ret = ov7670_init(client);
ret = ov7670_init(sd, 0);
if (ret < 0)
return ret;
ret = ov7670_read(client, REG_MIDH, &v);
ret = ov7670_read(sd, REG_MIDH, &v);
if (ret < 0)
return ret;
if (v != 0x7f) /* OV manuf. id. */
return -ENODEV;
ret = ov7670_read(client, REG_MIDL, &v);
ret = ov7670_read(sd, REG_MIDL, &v);
if (ret < 0)
return ret;
if (v != 0xa2)
@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client)
/*
* 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)
return ret;
if (v != 0x76) /* PID + VER = 0x76 / 0x73 */
return -ENODEV;
ret = ov7670_read(client, REG_VER, &v);
ret = ov7670_read(sd, REG_VER, &v);
if (ret < 0)
return ret;
if (v != 0x73) /* PID + VER = 0x76 / 0x73 */
@ -627,7 +640,7 @@ static struct ov7670_win_size {
/*
* 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 ret;
@ -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
* a mystery "edge offset" value in the top two bits of href.
*/
ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);
ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);
ret += ov7670_read(client, REG_HREF, &v);
ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff);
ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff);
ret += ov7670_read(sd, REG_HREF, &v);
v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
msleep(10);
ret += ov7670_write(client, REG_HREF, v);
ret += ov7670_write(sd, REG_HREF, v);
/*
* Vertical: similar arrangement, but only 10 bits.
*/
ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);
ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);
ret += ov7670_read(client, REG_VREF, &v);
ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff);
ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff);
ret += ov7670_read(sd, REG_VREF, &v);
v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);
msleep(10);
ret += ov7670_write(client, REG_VREF, v);
ret += ov7670_write(sd, REG_VREF, v);
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;
@ -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_win_size **ret_wsize)
{
@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
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.
*/
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;
struct ov7670_format_struct *ovfmt;
struct ov7670_win_size *wsize;
struct ov7670_info *info = i2c_get_clientdata(c);
unsigned char com7, clkrc;
struct ov7670_info *info = to_state(sd);
unsigned char com7, clkrc = 0;
ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
if (ret)
return ret;
/*
@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
* the colors.
*/
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)
return ret;
}
@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
*/
com7 = ovfmt->regs[0].value;
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
*/
ov7670_write_array(c, ovfmt->regs + 1);
ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
ov7670_write_array(sd, ovfmt->regs + 1);
ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart,
wsize->vstop);
ret = 0;
if (wsize->regs)
ret = ov7670_write_array(c, wsize->regs);
ret = ov7670_write_array(sd, wsize->regs);
info->fmt = ovfmt;
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;
}
@ -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
* 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;
unsigned char clkrc;
@ -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)
return -EINVAL;
ret = ov7670_read(c, REG_CLKRC, &clkrc);
ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0)
return ret;
memset(cp, 0, sizeof(struct v4l2_captureparm));
@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
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_fract *tpf = &cp->timeperframe;
@ -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.
*/
ret = ov7670_read(c, REG_CLKRC, &clkrc);
ret = ov7670_read(sd, REG_CLKRC, &clkrc);
if (ret < 0)
return ret;
if (tpf->numerator == 0 || tpf->denominator == 0)
@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
clkrc = (clkrc & 0x80) | div;
tpf->numerator = 1;
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)
static int ov7670_store_cmatrix(struct i2c_client *client,
static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
int matrix[CMATRIX_LEN])
{
int i, ret;
@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
* Weird crap seems to exist in the upper part of
* 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;
for (i = 0; i < CMATRIX_LEN; i++) {
@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client,
else
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;
}
@ -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 ret;
info->sat = value;
ov7670_calc_cmatrix(info, matrix);
ret = ov7670_store_cmatrix(client, matrix);
ret = ov7670_store_cmatrix(sd, matrix);
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;
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 ret;
@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value)
return -EINVAL;
info->hue = value;
ov7670_calc_cmatrix(info, matrix);
ret = ov7670_store_cmatrix(client, matrix);
ret = ov7670_store_cmatrix(sd, matrix);
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;
return 0;
@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v)
{
if ((v & 0x80) == 0)
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)
{
if (v > 127)
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;
int ret;
ov7670_read(client, REG_COM8, &com8);
ov7670_read(sd, REG_COM8, &com8);
com8 &= ~COM8_AEC;
ov7670_write(client, REG_COM8, com8);
ov7670_write(sd, REG_COM8, com8);
v = ov7670_abs_to_sm(value);
ret = ov7670_write(client, REG_BRIGHT, v);
ret = ov7670_write(sd, REG_BRIGHT, v);
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;
int ret = ov7670_read(client, REG_BRIGHT, &v);
int ret = ov7670_read(sd, REG_BRIGHT, &v);
*value = ov7670_sm_to_abs(v);
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;
int ret = ov7670_read(client, REG_CONTRAS, &v);
int ret = ov7670_read(sd, REG_CONTRAS, &v);
*value = v;
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;
unsigned char v = 0;
ret = ov7670_read(client, REG_MVFP, &v);
ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_MIRROR) == MVFP_MIRROR;
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;
int ret;
ret = ov7670_read(client, REG_MVFP, &v);
ret = ov7670_read(sd, REG_MVFP, &v);
if (value)
v |= MVFP_MIRROR;
else
v &= ~MVFP_MIRROR;
msleep(10); /* FIXME */
ret += ov7670_write(client, REG_MVFP, v);
ret += ov7670_write(sd, REG_MVFP, v);
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;
unsigned char v = 0;
ret = ov7670_read(client, REG_MVFP, &v);
ret = ov7670_read(sd, REG_MVFP, &v);
*value = (v & MVFP_FLIP) == MVFP_FLIP;
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;
int ret;
ret = ov7670_read(client, REG_MVFP, &v);
ret = ov7670_read(sd, REG_MVFP, &v);
if (value)
v |= MVFP_FLIP;
else
v &= ~MVFP_FLIP;
msleep(10); /* FIXME */
ret += ov7670_write(client, REG_MVFP, v);
ret += ov7670_write(sd, REG_MVFP, v);
return ret;
}
static struct ov7670_control {
struct v4l2_queryctrl qc;
int (*query)(struct i2c_client *c, __s32 *value);
int (*tweak)(struct i2c_client *c, int value);
int (*query)(struct v4l2_subdev *sd, __s32 *value);
int (*tweak)(struct v4l2_subdev *sd, int value);
} ov7670_controls[] =
{
{
@ -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 ov7670_control *ctrl = ov7670_find_control(qc->id);
@ -1211,161 +1228,128 @@ static int ov7670_queryctrl(struct i2c_client *client,
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);
int ret;
if (octrl == NULL)
return -EINVAL;
ret = octrl->query(client, &ctrl->value);
ret = octrl->query(sd, &ctrl->value);
if (ret >= 0)
return 0;
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);
int ret;
if (octrl == NULL)
return -EINVAL;
ret = octrl->tweak(client, ctrl->value);
ret = octrl->tweak(sd, ctrl->value);
if (ret >= 0)
return 0;
return ret;
}
/*
* Basic i2c stuff.
*/
static struct i2c_driver ov7670_driver;
static int ov7670_attach(struct i2c_adapter *adapter)
static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
int ret;
struct i2c_client *client;
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,
};
/* ----------------------------------------------------------------------- */
static int ov7670_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct v4l2_subdev *sd;
struct ov7670_info *info;
int ret;
/*
* 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;
client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
if (! client)
info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
client->adapter = adapter;
client->addr = OV7670_I2C_ADDR;
client->driver = &ov7670_driver,
strcpy(client->name, "OV7670");
/*
* Set up our info structure.
*/
info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
if (! info) {
ret = -ENOMEM;
goto out_free;
sd = &info->sd;
v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
/* Make sure it's an ov7670 */
ret = ov7670_detect(sd);
if (ret) {
v4l_dbg(1, debug, client,
"chip found @ 0x%x (%s) is not an ov7670 chip.\n",
client->addr << 1, client->adapter->name);
kfree(info);
return ret;
}
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
info->fmt = &ov7670_formats[0];
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;
out_free_info:
kfree(info);
out_free:
kfree(client);
return ret;
}
static int ov7670_detach(struct i2c_client *client)
{
i2c_detach_client(client);
kfree(i2c_get_clientdata(client));
kfree(client);
return 0;
}
static int ov7670_command(struct i2c_client *client, unsigned int cmd,
void *arg)
static int ov7670_remove(struct i2c_client *client)
{
switch (cmd) {
case VIDIOC_DBG_G_CHIP_IDENT:
return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0);
struct v4l2_subdev *sd = i2c_get_clientdata(client);
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;
v4l2_device_unregister_subdev(sd);
kfree(to_state(sd));
return 0;
}
static struct i2c_driver ov7670_driver = {
.driver = {
.name = "ov7670",
},
.id = I2C_DRIVERID_OV7670,
.attach_adapter = ov7670_attach,
.detach_client = ov7670_detach,
.command = ov7670_command,
static const struct i2c_device_id ov7670_id[] = {
{ "ov7670", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, 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);
static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.name = "ov7670",
.command = ov7670_command,
.probe = ov7670_probe,
.remove = ov7670_remove,
.legacy_class = I2C_CLASS_TV_ANALOG,
.id_table = ov7670_id,
};