Hello,
I am working with a gumstix overo board connected with a e-con-systems camera module using a ov3640 camera sensor.
Along with the board I got a camera driver which can be used with linux kernel 2.6.34, but I want to use the camera along with the linux kernel 3.5.
So I tried to implement the driver into the kernel sources by referring to an existing driver (/driver/media/video/ov9640.c).
But the i2c_transfer fails. The older driver configured before the use of i2c some pins and set clock and so on, but I thought when I use the "v4l2-subdev-api" these things should be done automatically. Am I right?
Can some help me out?
Here is my codesnippet:
static int ov3640_reg_read(struct i2c_client *client, u16 reg, u8 *val)
{
int ret;
u8 data[2] = {0};
struct i2c_msg msg = {
.addr = client->addr,
.flags = 0,
.len = 2,
.buf = data,
};
data[0] = (u8)(reg >> 8);
data[1] = (u8)(reg & 0xff);
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret < 0)
goto err;
msg.flags = I2C_M_RD;
msg.len = 1;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret < 0)
goto err;
*val = data[0];
return 0;
err:
dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
return ret;
}
struct ov3640 {
struct v4l2_subdev subdev;
struct v4l2_subdev_sensor_interface_parms *plat_parms;
struct v4l2_fract timeperframe;
int i_size;
int i_fmt;
int ver;
int fps;
};
static struct ov3640 *to_ov3640(const struct i2c_client *client)
{
return container_of(i2c_get_clientdata(client), struct ov3640, subdev);
}
static int ov3640_detect(struct i2c_client *client)
{
u8 pidh, pidl;
if (!client)
return -ENODEV;
if (ov3640_reg_read(client, 0x300A, &pidh))
return -ENODEV;
if (ov3640_reg_read(client, 0x300B, &pidl))
return -ENODEV;
if ((pidh == 0x36) && ((pidl == 0x41) || (pidl == 0x4C)))
{
dev_info(&client->dev, "Detect success (%02X,%02X)\n", pidh, pidl);
return pidl;
}
return -ENODEV;
}
static int ov3640_video_probe(struct soc_camera_device *icd, struct i2c_client *client)
{
struct ov3640 *ov3640 = to_ov3640(client);
int ver;
ver = ov3640_detect(client);
if (ver < 0)
{
dev_err(&client->dev, "Unable to detect sensor, err %d\n", ver);
return ver;
}
ov3640->ver = ver;
dev_dbg(&client->dev, "Chip version 0x%02x detected\n", ov3640->ver);
return 0;
}
/* ----------------------------------------------------------------------- */
static const struct v4l2_queryctrl ov3640_controls[] = {};
static struct v4l2_subdev_core_ops ov3640_subdev_core_ops = {
.g_chip_ident = test2,
.g_ctrl = test2,
.s_ctrl = test2,
};
static struct v4l2_subdev_video_ops ov3640_subdev_video_ops = {
.s_stream = test2,
.try_mbus_fmt = test2,
.s_mbus_fmt = test2,
.g_mbus_fmt = test2,
.enum_mbus_fmt = test2,
.enum_framesizes = test2,
.enum_frameintervals = test2,
.g_parm = test2,
.s_parm = test2,
};
static struct v4l2_subdev_sensor_ops ov3640_subdev_sensor_ops = {
.g_skip_frames = test2,
};
static struct v4l2_subdev_ops ov3640_subdev_ops = {
.core = &ov3640_subdev_core_ops,
.video = &ov3640_subdev_video_ops,
.sensor = &ov3640_subdev_sensor_ops,
};
/* ----------------------------------------------------------------------- */
/************************************************************************************************************
*
* MODULE TYPE : FUNCTION MODULE ID :
* Name : ov3640_probe
* Parameter1 : struct i2c_client *client
* Parameter2 : const struct i2c_device_id *id
* Returns : LINT32 - On sucess returns 0
* - On Failure a negative number be returned
*
* Description : Configure the gpio levels for ov3640 driver
* Comments :
************************************************************************************************************/
static INT32 ov3640_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
cam_interface_pin_config *pin = NULL;
struct ov3640 *ov3640;
if(!client->dev.platform_data)
printk("TOM OV3640 PROBE PLATFORM NULL ##########\n");
struct soc_camera_device *icd = client->dev.platform_data;
struct soc_camera_link *icl;
int ret;
if (!icd) {
dev_err(&client->dev, "OV3640: missing soc-camera data!\n");
return -EINVAL;
}
icl = soc_camera_i2c_to_link(client);
if (!icl) {
dev_err(&client->dev, "OV3640 driver needs platform data\n");
return -EINVAL;
}
if (!icl->priv) {
dev_err(&client->dev, "OV3640 driver needs i/f platform data\n");
return -EINVAL;
}
ov3640 = kzalloc(sizeof(struct ov3640), GFP_KERNEL);
if (!ov3640)
return -ENOMEM;
v4l2_i2c_subdev_init(&ov3640->subdev, client, &ov3640_subdev_ops);
ov3640->i_fmt = 0; /* First format in the list */
ov3640->timeperframe.numerator = 1;
ov3640->timeperframe.denominator = 15;
ov3640->plat_parms = icl->priv;
if ((pin = kmalloc(sizeof(cam_interface_pin_config), GFP_KERNEL)) == NULL)
{
printk(KERN_ERR "Failed to allocate memory for pins\n");
}
all_clk_enable();
init_omap_hwr(pin);
ret = ov3640_video_probe(icd, client);
if (ret) {
kfree(ov3640);
}
return 0;
}
static const struct i2c_device_id ov3640_id[] = {
{ "ov3640", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ov3640_id);
static const unsigned short normal_i2c[] = {
0x3C, 0xfffeU };
static struct i2c_driver ov3640_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.owner = THIS_MODULE,
.name = "ov3640",
},
.probe = ov3640_probe,
.remove = __exit_p(ov3640_remove),
.id_table = ov3640_id,
};
module_i2c_driver(ov3640_driver);
MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 3640 sensor");
MODULE_AUTHOR("Test");
MODULE_LICENSE("GPL v2");
Regards, Tom