⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcm825x.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
	control = find_vctrl(qc->id);	if (control == NULL)		return -EINVAL;	*qc = control->qc;	return 0;}static int ioctl_g_ctrl(struct v4l2_int_device *s,			     struct v4l2_control *vc){	struct tcm825x_sensor *sensor = s->priv;	struct i2c_client *client = sensor->i2c_client;	int val, r;	struct vcontrol *lvc;	/* exposure time is special, spread accross 2 registers */	if (vc->id == V4L2_CID_EXPOSURE) {		int val_lower, val_upper;		val_upper = tcm825x_read_reg(client,					     TCM825X_ADDR(TCM825X_ESRSPD_U));		if (val_upper < 0)			return val_upper;		val_lower = tcm825x_read_reg(client,					     TCM825X_ADDR(TCM825X_ESRSPD_L));		if (val_lower < 0)			return val_lower;		vc->value = ((val_upper & 0x1f) << 8) | (val_lower);		return 0;	}	lvc = find_vctrl(vc->id);	if (lvc == NULL)		return -EINVAL;	r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));	if (r < 0)		return r;	val = r & TCM825X_MASK(lvc->reg);	val >>= lvc->start_bit;	if (val < 0)		return val;	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)		val ^= sensor->platform_data->is_upside_down();	vc->value = val;	return 0;}static int ioctl_s_ctrl(struct v4l2_int_device *s,			     struct v4l2_control *vc){	struct tcm825x_sensor *sensor = s->priv;	struct i2c_client *client = sensor->i2c_client;	struct vcontrol *lvc;	int val = vc->value;	/* exposure time is special, spread accross 2 registers */	if (vc->id == V4L2_CID_EXPOSURE) {		int val_lower, val_upper;		val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);		val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);		if (tcm825x_write_reg_mask(client,					   TCM825X_ESRSPD_U, val_upper))			return -EIO;		if (tcm825x_write_reg_mask(client,					   TCM825X_ESRSPD_L, val_lower))			return -EIO;		return 0;	}	lvc = find_vctrl(vc->id);	if (lvc == NULL)		return -EINVAL;	if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)		val ^= sensor->platform_data->is_upside_down();	val = val << lvc->start_bit;	if (tcm825x_write_reg_mask(client, lvc->reg, val))		return -EIO;	return 0;}static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,				   struct v4l2_fmtdesc *fmt){	int index = fmt->index;	switch (fmt->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		if (index >= TCM825X_NUM_CAPTURE_FORMATS)			return -EINVAL;		break;	default:		return -EINVAL;	}	fmt->flags = tcm825x_formats[index].flags;	strlcpy(fmt->description, tcm825x_formats[index].description,		sizeof(fmt->description));	fmt->pixelformat = tcm825x_formats[index].pixelformat;	return 0;}static int ioctl_try_fmt_cap(struct v4l2_int_device *s,			     struct v4l2_format *f){	struct tcm825x_sensor *sensor = s->priv;	enum image_size isize;	int ifmt;	struct v4l2_pix_format *pix = &f->fmt.pix;	isize = tcm825x_find_size(s, pix->width, pix->height);	dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",		isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);	pix->width = tcm825x_sizes[isize].width;	pix->height = tcm825x_sizes[isize].height;	for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)		if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)			break;	if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)		ifmt = 0;	/* Default = YUV 4:2:2 */	pix->pixelformat = tcm825x_formats[ifmt].pixelformat;	pix->field = V4L2_FIELD_NONE;	pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;	pix->sizeimage = pix->bytesperline * pix->height;	pix->priv = 0;	dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",		pix->pixelformat);	switch (pix->pixelformat) {	case V4L2_PIX_FMT_UYVY:	default:		pix->colorspace = V4L2_COLORSPACE_JPEG;		break;	case V4L2_PIX_FMT_RGB565:		pix->colorspace = V4L2_COLORSPACE_SRGB;		break;	}	return 0;}static int ioctl_s_fmt_cap(struct v4l2_int_device *s,				struct v4l2_format *f){	struct tcm825x_sensor *sensor = s->priv;	struct v4l2_pix_format *pix = &f->fmt.pix;	int rval;	rval = ioctl_try_fmt_cap(s, f);	if (rval)		return rval;	rval = tcm825x_configure(s);	sensor->pix = *pix;	return rval;}static int ioctl_g_fmt_cap(struct v4l2_int_device *s,				struct v4l2_format *f){	struct tcm825x_sensor *sensor = s->priv;	f->fmt.pix = sensor->pix;	return 0;}static int ioctl_g_parm(struct v4l2_int_device *s,			     struct v4l2_streamparm *a){	struct tcm825x_sensor *sensor = s->priv;	struct v4l2_captureparm *cparm = &a->parm.capture;	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	memset(a, 0, sizeof(*a));	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	cparm->capability = V4L2_CAP_TIMEPERFRAME;	cparm->timeperframe = sensor->timeperframe;	return 0;}static int ioctl_s_parm(struct v4l2_int_device *s,			     struct v4l2_streamparm *a){	struct tcm825x_sensor *sensor = s->priv;	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;	u32 tgt_fps;	/* target frames per secound */	int rval;	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if ((timeperframe->numerator == 0)	    || (timeperframe->denominator == 0)) {		timeperframe->denominator = DEFAULT_FPS;		timeperframe->numerator = 1;	}	tgt_fps = timeperframe->denominator / timeperframe->numerator;	if (tgt_fps > MAX_FPS) {		timeperframe->denominator = MAX_FPS;		timeperframe->numerator = 1;	} else if (tgt_fps < MIN_FPS) {		timeperframe->denominator = MIN_FPS;		timeperframe->numerator = 1;	}	sensor->timeperframe = *timeperframe;	rval = tcm825x_configure(s);	return rval;}static int ioctl_s_power(struct v4l2_int_device *s, int on){	struct tcm825x_sensor *sensor = s->priv;	return sensor->platform_data->power_set(on);}/* * Given the image capture format in pix, the nominal frame period in * timeperframe, calculate the required xclk frequency. * * TCM825X input frequency characteristics are: *     Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz */static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p){	struct tcm825x_sensor *sensor = s->priv;	struct v4l2_fract *timeperframe = &sensor->timeperframe;	u32 tgt_xclk;	/* target xclk */	u32 tgt_fps;	/* target frames per secound */	int rval;	rval = sensor->platform_data->ifparm(p);	if (rval)		return rval;	tgt_fps = timeperframe->denominator / timeperframe->numerator;	tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?		(2457 * tgt_fps) / MAX_HALF_FPS :		(2457 * tgt_fps) / MAX_FPS;	tgt_xclk *= 10000;	tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);	tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);	p->u.bt656.clock_curr = tgt_xclk;	return 0;}static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf){	struct tcm825x_sensor *sensor = s->priv;	return sensor->platform_data->needs_reset(s, buf, &sensor->pix);}static int ioctl_reset(struct v4l2_int_device *s){	return -EBUSY;}static int ioctl_init(struct v4l2_int_device *s){	return tcm825x_configure(s);}static int ioctl_dev_exit(struct v4l2_int_device *s){	return 0;}static int ioctl_dev_init(struct v4l2_int_device *s){	struct tcm825x_sensor *sensor = s->priv;	int r;	r = tcm825x_read_reg(sensor->i2c_client, 0x01);	if (r < 0)		return r;	if (r == 0) {		dev_err(&sensor->i2c_client->dev, "device not detected\n");		return -EIO;	}	return 0;}static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {	{ vidioc_int_dev_init_num,	  (v4l2_int_ioctl_func *)ioctl_dev_init },	{ vidioc_int_dev_exit_num,	  (v4l2_int_ioctl_func *)ioctl_dev_exit },	{ vidioc_int_s_power_num,	  (v4l2_int_ioctl_func *)ioctl_s_power },	{ vidioc_int_g_ifparm_num,	  (v4l2_int_ioctl_func *)ioctl_g_ifparm },	{ vidioc_int_g_needs_reset_num,	  (v4l2_int_ioctl_func *)ioctl_g_needs_reset },	{ vidioc_int_reset_num,	  (v4l2_int_ioctl_func *)ioctl_reset },	{ vidioc_int_init_num,	  (v4l2_int_ioctl_func *)ioctl_init },	{ vidioc_int_enum_fmt_cap_num,	  (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },	{ vidioc_int_try_fmt_cap_num,	  (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },	{ vidioc_int_g_fmt_cap_num,	  (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },	{ vidioc_int_s_fmt_cap_num,	  (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },	{ vidioc_int_g_parm_num,	  (v4l2_int_ioctl_func *)ioctl_g_parm },	{ vidioc_int_s_parm_num,	  (v4l2_int_ioctl_func *)ioctl_s_parm },	{ vidioc_int_queryctrl_num,	  (v4l2_int_ioctl_func *)ioctl_queryctrl },	{ vidioc_int_g_ctrl_num,	  (v4l2_int_ioctl_func *)ioctl_g_ctrl },	{ vidioc_int_s_ctrl_num,	  (v4l2_int_ioctl_func *)ioctl_s_ctrl },};static struct v4l2_int_slave tcm825x_slave = {	.ioctls = tcm825x_ioctl_desc,	.num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),};static struct tcm825x_sensor tcm825x;static struct v4l2_int_device tcm825x_int_device = {	.module = THIS_MODULE,	.name = TCM825X_NAME,	.priv = &tcm825x,	.type = v4l2_int_type_slave,	.u = {		.slave = &tcm825x_slave,	},};#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)static int tcm825x_probe(struct i2c_client *client)#elsestatic int tcm825x_probe(struct i2c_client *client,			 const struct i2c_device_id *did)#endif{	struct tcm825x_sensor *sensor = &tcm825x;	int rval;	if (i2c_get_clientdata(client))		return -EBUSY;	sensor->platform_data = client->dev.platform_data;	if (sensor->platform_data == NULL	    || !sensor->platform_data->is_okay())		return -ENODEV;	sensor->v4l2_int_device = &tcm825x_int_device;	sensor->i2c_client = client;	i2c_set_clientdata(client, sensor);	/* Make the default capture format QVGA RGB565 */	sensor->pix.width = tcm825x_sizes[QVGA].width;	sensor->pix.height = tcm825x_sizes[QVGA].height;	sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;	rval = v4l2_int_device_register(sensor->v4l2_int_device);	if (rval)		i2c_set_clientdata(client, NULL);	return rval;}static int __exit tcm825x_remove(struct i2c_client *client){	struct tcm825x_sensor *sensor = i2c_get_clientdata(client);	if (!client->adapter)		return -ENODEV;	/* our client isn't attached */	v4l2_int_device_unregister(sensor->v4l2_int_device);	i2c_set_clientdata(client, NULL);	return 0;}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)static const struct i2c_device_id tcm825x_id[] = {	{ "tcm825x", 0 },	{ }};MODULE_DEVICE_TABLE(i2c, tcm825x_id);#endifstatic struct i2c_driver tcm825x_i2c_driver = {	.driver	= {		.name = TCM825X_NAME,	},	.probe	= tcm825x_probe,	.remove	= __exit_p(tcm825x_remove),#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)	.id_table = tcm825x_id,#endif};static struct tcm825x_sensor tcm825x = {	.timeperframe = {		.numerator   = 1,		.denominator = DEFAULT_FPS,	},};static int __init tcm825x_init(void){	int rval;	rval = i2c_add_driver(&tcm825x_i2c_driver);	if (rval)		printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",		       __func__);	return rval;}static void __exit tcm825x_exit(void){	i2c_del_driver(&tcm825x_i2c_driver);}/* * FIXME: Menelaus isn't ready (?) at module_init stage, so use * late_initcall for now. */late_initcall(tcm825x_init);module_exit(tcm825x_exit);MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");MODULE_DESCRIPTION("TCM825x camera sensor driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -