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:
parent
2da9479aaa
commit
14386c2b77
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user