implement ov3640 driver using subdev-api with omap3-isp

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 
(https://github.com/scottellis/econ-cam-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 a existing drivers like /driver/media/video/ov9640.c 
and /driver/media/video/mt9v032.c.

The old driver has an isp implementation integrated 
and it registers itself once as a video device. 
So the application which is going to use the camera 
sensor just needs to open the right video device 
and by calling ioctl the corresponding functions will be called. 

By going through the linux 3.5 kernel sources 
I found out that the omap3-isp registers itself 
as an video-device and should support sensors using the
v4l2-subdev interface. 

So am I right when I think that I just need to 
add the ov3640 subdev to the isp_v4l2_subdevs_group 
in the board-overo.c file and then just open the 
video device of the isp to use it via application (ioctl)?

I read an article which told me that I need to use the 
v4l2_subdev_pad_ops to interact from isp with 
the ov3640 subdev, but it does not work. 
I don't know what I am doing wrong.

Is there already an implemenation of the ov3640 
using subdev-api which I couldn't find 
or can someone give me a hint what I need to do to get the 
sensor with the isp working?

My Code Snippet board-overo.c:

#define LM3553_SLAVE_ADDRESS	0x53
#define OV3640_I2C_ADDR		(0x78 >> 1)
int omap3evm_ov3640_platform_data;
int lm3553_platform_data;

static struct i2c_board_info omap3_i2c_boardinfo_ov3640 = {
		I2C_BOARD_INFO("ov3640", OV3640_I2C_ADDR),
		.platform_data = &omap3evm_ov3640_platform_data,
};

static struct i2c_board_info omap3_i2c_boardinfo_lm3553 = {
		I2C_BOARD_INFO("lm3553",LM3553_SLAVE_ADDRESS),
		.platform_data = &lm3553_platform_data,
};

static struct i2c_board_info mt9v032_i2c_device = {
	I2C_BOARD_INFO("mt9v032", MT9V032_I2C_ADDR),
	.platform_data = &mt9v032_platform_data,
};

/*static struct isp_subdev_i2c_board_info mt9v032_subdevs[] = {
	{
		.board_info = &mt9v032_i2c_device,
		.i2c_adapter_id = MT9V032_I2C_BUS_NUM,
	},
	{ NULL, 0, },
};*/

static struct isp_subdev_i2c_board_info overo_subdevs[] = {
	/*{
		.board_info = &mt9v032_i2c_device,
		.i2c_adapter_id = MT9V032_I2C_BUS_NUM,
	},*/
	{
		.board_info = &omap3_i2c_boardinfo_ov3640,
		.i2c_adapter_id = MT9V032_I2C_BUS_NUM,
	},
	{ NULL, 0, },
};

static struct isp_v4l2_subdevs_group overo_camera_subdevs[] = {
	{
		//.subdevs = mt9v032_subdevs,
		.subdevs = overo_subdevs,
		.interface = ISP_INTERFACE_PARALLEL,
		.bus = {
				.parallel = {
					.data_lane_shift = 0,
					.clk_pol = 0,
					.bridge = ISPCTRL_PAR_BRIDGE_DISABLE,
				}
		},
	},
	{ NULL, 0, },
};

static struct isp_platform_data overo_isp_platform_data = {
	.subdevs = overo_camera_subdevs,
};

static int __init overo_camera_init(void)
{
       return omap3_init_camera(&overo_isp_platform_data);
}



My Code Snippet ov3640.c:

static struct v4l2_subdev_pad_ops ov3640_subdev_pad_ops = {
	.enum_mbus_code = test2,
	.enum_frame_size = test2,
	.get_fmt = test2,
	.set_fmt = test2,
	.get_crop = test2,
	.set_crop = test2,
};

static struct v4l2_subdev_core_ops ov3640_subdev_core_ops = {
	.g_chip_ident	= test2,
	.g_ctrl		= test2,
	.s_ctrl		= test2,
	//.g_register	= test2,
	//.s_register	= 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,
	//.g_interface_parms = test2,
};

static struct v4l2_subdev_ops ov3640_subdev_ops = {
	.core	= &ov3640_subdev_core_ops,
	.video	= &ov3640_subdev_video_ops,
	.sensor	= &ov3640_subdev_sensor_ops,
	.pad	= &ov3640_subdev_pad_ops,
};

/*static struct soc_camera_ops ov3640_ops = {

	.set_bus_param		= test2,

	.query_bus_param	= test2,

	.controls		= ov3640_controls,

	.num_controls		= ARRAY_SIZE(ov3640_controls),

};*/

static int mt9v032_registered(struct v4l2_subdev *subdev)
{
	printk("TOM OPEN NEW ##########\n");
	return 0;
}

static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
	printk("TOM OPEN NEW ##########\n");
	return 0;
}

static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
	printk("TOM CLOSE NEW ##########\n");
	return 0;
	//return mt9v032_set_power(subdev, 0);
}

static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
	.registered = mt9v032_registered,
	.open = mt9v032_open,
	.close = mt9v032_close,
};


static INT32 ov3640_probe(struct i2c_client *client, const struct
i2c_device_id *id)
{
	FNRESLT ret_val;
	cam_data *cam;
	struct soc_camera_link *icl;
	struct v4l2_subdev *sd;

	int ret;

	cam = kzalloc(sizeof(cam_data), GFP_KERNEL);

	if (!cam)
		return -ENOMEM;
	
	ret_val	= v4l2_base_struct(&cam,SET_ADDRESS);
	if(CHECK_IN_FAIL_LIMIT(ret_val))
	{
		printk(KERN_ERR "Failed to register the camera device\n");
		//TRACE_ERR_AND_RET(FAIL);
	}

	ret_val	= init_phy_mem();
	/*if(CHECK_IN_FAIL_LIMIT(ret_val))
	{
		goto exit;
	}*/

	if (!i2c_check_functionality(client->adapter,
				     I2C_FUNC_SMBUS_WORD_DATA)) {
		dev_warn(&client->adapter->dev,
			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
		return -EIO;
	}
	
	sd = &cam->subdev;
	cam->cam_sensor.client = client;

	v4l2_i2c_subdev_init(sd, client, &ov3640_subdev_ops);
	printk("TOM SUBDEV NAME: %s ##########\n",sd->name);
	sd->internal_ops = &mt9v032_subdev_internal_ops;

	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;

	cam->pad.flags = MEDIA_PAD_FL_SOURCE;

	ret = media_entity_init(&sd->entity, 1, &cam->pad, 0);

	printk("TOM OV3640 PROBE PAD %08x ##########\n",&cam->pad);

/*********************************************************/
	gpio_request(RESET_GPIO,"ov3640");
	gpio_request(STANDBY_GPIO,"ov3640");

	gpio_direction_output(RESET_GPIO, true);
	gpio_direction_output(STANDBY_GPIO, true);
	/* Turn ON Omnivision sensor */
	gpio_set_value(RESET_GPIO, ENABLE);
	gpio_set_value(STANDBY_GPIO, DISABLE);
	udelay(100);

	/* RESET Omnivision sensor */
	gpio_set_value(RESET_GPIO, DISABLE);
	udelay(100);
	gpio_set_value(RESET_GPIO, ENABLE);

	udelay(100);
/*********************************************************/
	//ret = ov3640_video_probe(client);

	if (ret) {

		//icd->ops = NULL;

		kfree(cam);
	}

	ret_val	= ov3640_init(cam);
	if(CHECK_IN_FAIL_LIMIT(ret_val))
	{
		return ret_val;
	}

	return 0;
}

static const struct i2c_device_id ov3640_id[] = {
	{ "ov3640", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, ov3640_id);

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,
};

Regards, Tom


--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux