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

📄 tcm825x.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * drivers/media/video/tcm825x.c * * TCM825X camera sensor driver. * * Copyright (C) 2007 Nokia Corporation. * * Contact: Sakari Ailus <sakari.ailus@nokia.com> * * Based on code from David Cohen <david.cohen@indt.org.br> * * This driver was based on ov9640 sensor driver from MontaVista * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */#include <linux/i2c.h>#include <media/v4l2-int-device.h>#include "tcm825x.h"/* * The sensor has two fps modes: the lower one just gives half the fps * at the same xclk than the high one. */#define MAX_FPS 30#define MIN_FPS 8#define MAX_HALF_FPS (MAX_FPS / 2)#define HIGH_FPS_MODE_LOWER_LIMIT 14#define DEFAULT_FPS MAX_HALF_FPSstruct tcm825x_sensor {	const struct tcm825x_platform_data *platform_data;	struct v4l2_int_device *v4l2_int_device;	struct i2c_client *i2c_client;	struct v4l2_pix_format pix;	struct v4l2_fract timeperframe;};/* list of image formats supported by TCM825X sensor */const static struct v4l2_fmtdesc tcm825x_formats[] = {	{		.description = "YUYV (YUV 4:2:2), packed",		.pixelformat = V4L2_PIX_FMT_UYVY,	}, {		/* Note:  V4L2 defines RGB565 as:		 *		 *      Byte 0                    Byte 1		 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3		 *		 * We interpret RGB565 as:		 *		 *      Byte 0                    Byte 1		 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3		 */		.description = "RGB565, le",		.pixelformat = V4L2_PIX_FMT_RGB565,	},};#define TCM825X_NUM_CAPTURE_FORMATS	ARRAY_SIZE(tcm825x_formats)/* * TCM825X register configuration for all combinations of pixel format and * image size */const static struct tcm825x_reg subqcif	=	{ 0x20, TCM825X_PICSIZ };const static struct tcm825x_reg qcif	=	{ 0x18, TCM825X_PICSIZ };const static struct tcm825x_reg cif	=	{ 0x14, TCM825X_PICSIZ };const static struct tcm825x_reg qqvga	=	{ 0x0c, TCM825X_PICSIZ };const static struct tcm825x_reg qvga	=	{ 0x04, TCM825X_PICSIZ };const static struct tcm825x_reg vga	=	{ 0x00, TCM825X_PICSIZ };const static struct tcm825x_reg yuv422	=	{ 0x00, TCM825X_PICFMT };const static struct tcm825x_reg rgb565	=	{ 0x02, TCM825X_PICFMT };/* Our own specific controls */#define V4L2_CID_ALC				V4L2_CID_PRIVATE_BASE#define V4L2_CID_H_EDGE_EN			V4L2_CID_PRIVATE_BASE + 1#define V4L2_CID_V_EDGE_EN			V4L2_CID_PRIVATE_BASE + 2#define V4L2_CID_LENS				V4L2_CID_PRIVATE_BASE + 3#define V4L2_CID_MAX_EXPOSURE_TIME		V4L2_CID_PRIVATE_BASE + 4#define V4L2_CID_LAST_PRIV			V4L2_CID_MAX_EXPOSURE_TIME/*  Video controls  */static struct vcontrol {	struct v4l2_queryctrl qc;	u16 reg;	u16 start_bit;} video_control[] = {	{		{			.id = V4L2_CID_GAIN,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Gain",			.minimum = 0,			.maximum = 63,			.step = 1,		},		.reg = TCM825X_AG,		.start_bit = 0,	},	{		{			.id = V4L2_CID_RED_BALANCE,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Red Balance",			.minimum = 0,			.maximum = 255,			.step = 1,		},		.reg = TCM825X_MRG,		.start_bit = 0,	},	{		{			.id = V4L2_CID_BLUE_BALANCE,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Blue Balance",			.minimum = 0,			.maximum = 255,			.step = 1,		},		.reg = TCM825X_MBG,		.start_bit = 0,	},	{		{			.id = V4L2_CID_AUTO_WHITE_BALANCE,			.type = V4L2_CTRL_TYPE_BOOLEAN,			.name = "Auto White Balance",			.minimum = 0,			.maximum = 1,			.step = 0,		},		.reg = TCM825X_AWBSW,		.start_bit = 7,	},	{		{			.id = V4L2_CID_EXPOSURE,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Exposure Time",			.minimum = 0,			.maximum = 0x1fff,			.step = 1,		},		.reg = TCM825X_ESRSPD_U,		.start_bit = 0,	},	{		{			.id = V4L2_CID_HFLIP,			.type = V4L2_CTRL_TYPE_BOOLEAN,			.name = "Mirror Image",			.minimum = 0,			.maximum = 1,			.step = 0,		},		.reg = TCM825X_H_INV,		.start_bit = 6,	},	{		{			.id = V4L2_CID_VFLIP,			.type = V4L2_CTRL_TYPE_BOOLEAN,			.name = "Vertical Flip",			.minimum = 0,			.maximum = 1,			.step = 0,		},		.reg = TCM825X_V_INV,		.start_bit = 7,	},	/* Private controls */	{		{			.id = V4L2_CID_ALC,			.type = V4L2_CTRL_TYPE_BOOLEAN,			.name = "Auto Luminance Control",			.minimum = 0,			.maximum = 1,			.step = 0,		},		.reg = TCM825X_ALCSW,		.start_bit = 7,	},	{		{			.id = V4L2_CID_H_EDGE_EN,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Horizontal Edge Enhancement",			.minimum = 0,			.maximum = 0xff,			.step = 1,		},		.reg = TCM825X_HDTG,		.start_bit = 0,	},	{		{			.id = V4L2_CID_V_EDGE_EN,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Vertical Edge Enhancement",			.minimum = 0,			.maximum = 0xff,			.step = 1,		},		.reg = TCM825X_VDTG,		.start_bit = 0,	},	{		{			.id = V4L2_CID_LENS,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Lens Shading Compensation",			.minimum = 0,			.maximum = 0x3f,			.step = 1,		},		.reg = TCM825X_LENS,		.start_bit = 0,	},	{		{			.id = V4L2_CID_MAX_EXPOSURE_TIME,			.type = V4L2_CTRL_TYPE_INTEGER,			.name = "Maximum Exposure Time",			.minimum = 0,			.maximum = 0x3,			.step = 1,		},		.reg = TCM825X_ESRLIM,		.start_bit = 5,	},};const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] ={ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] ={ &yuv422, &rgb565 };/* * Read a value from a register in an TCM825X sensor device.  The value is * returned in 'val'. * Returns zero if successful, or non-zero otherwise. */static int tcm825x_read_reg(struct i2c_client *client, int reg){	int err;	struct i2c_msg msg[2];	u8 reg_buf, data_buf = 0;	if (!client->adapter)		return -ENODEV;	msg[0].addr = client->addr;	msg[0].flags = 0;	msg[0].len = 1;	msg[0].buf = &reg_buf;	msg[1].addr = client->addr;	msg[1].flags = I2C_M_RD;	msg[1].len = 1;	msg[1].buf = &data_buf;	reg_buf = reg;	err = i2c_transfer(client->adapter, msg, 2);	if (err < 0)		return err;	return data_buf;}/* * Write a value to a register in an TCM825X sensor device. * Returns zero if successful, or non-zero otherwise. */static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val){	int err;	struct i2c_msg msg[1];	unsigned char data[2];	if (!client->adapter)		return -ENODEV;	msg->addr = client->addr;	msg->flags = 0;	msg->len = 2;	msg->buf = data;	data[0] = reg;	data[1] = val;	err = i2c_transfer(client->adapter, msg, 1);	if (err >= 0)		return 0;	return err;}static int __tcm825x_write_reg_mask(struct i2c_client *client,				    u8 reg, u8 val, u8 mask){	int rc;	/* need to do read - modify - write */	rc = tcm825x_read_reg(client, reg);	if (rc < 0)		return rc;	rc &= (~mask);	/* Clear the masked bits */	val &= mask;	/* Enforce mask on value */	val |= rc;	/* write the new value to the register */	rc = tcm825x_write_reg(client, reg, val);	if (rc)		return rc;	return 0;}#define tcm825x_write_reg_mask(client, regmask, val)			\	__tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val,	\				 TCM825X_MASK((regmask)))/* * Initialize a list of TCM825X registers. * The list of registers is terminated by the pair of values * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. * Returns zero if successful, or non-zero otherwise. */static int tcm825x_write_default_regs(struct i2c_client *client,				      const struct tcm825x_reg *reglist){	int err;	const struct tcm825x_reg *next = reglist;	while (!((next->reg == TCM825X_REG_TERM)		 && (next->val == TCM825X_VAL_TERM))) {		err = tcm825x_write_reg(client, next->reg, next->val);		if (err) {			dev_err(&client->dev, "register writing failed\n");			return err;		}		next++;	}	return 0;}static struct vcontrol *find_vctrl(int id){	int i;	if (id < V4L2_CID_BASE)		return NULL;	for (i = 0; i < ARRAY_SIZE(video_control); i++)		if (video_control[i].qc.id == id)			return &video_control[i];	return NULL;}/* * Find the best match for a requested image capture size.  The best match * is chosen as the nearest match that has the same number or fewer pixels * as the requested size, or the smallest image size if the requested size * has fewer pixels than the smallest image. */static enum image_size tcm825x_find_size(struct v4l2_int_device *s,					 unsigned int width,					 unsigned int height){	enum image_size isize;	unsigned long pixels = width * height;	struct tcm825x_sensor *sensor = s->priv;	for (isize = subQCIF; isize < VGA; isize++) {		if (tcm825x_sizes[isize + 1].height		    * tcm825x_sizes[isize + 1].width > pixels) {			dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);			return isize;		}	}	dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");	return VGA;}/* * Configure the TCM825X for current image size, pixel format, and * frame period. fper is the frame period (in seconds) expressed as a * fraction. Returns zero if successful, or non-zero otherwise. The * actual frame period is returned in fper. */static int tcm825x_configure(struct v4l2_int_device *s){	struct tcm825x_sensor *sensor = s->priv;	struct v4l2_pix_format *pix = &sensor->pix;	enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);	struct v4l2_fract *fper = &sensor->timeperframe;	enum pixel_format pfmt;	int err;	u32 tgt_fps;	u8 val;	/* common register initialization */	err = tcm825x_write_default_regs(		sensor->i2c_client, sensor->platform_data->default_regs());	if (err)		return err;	/* configure image size */	val = tcm825x_siz_reg[isize]->val;	dev_dbg(&sensor->i2c_client->dev,		"configuring image size %d\n", isize);	err = tcm825x_write_reg_mask(sensor->i2c_client,				     tcm825x_siz_reg[isize]->reg, val);	if (err)		return err;	/* configure pixel format */	switch (pix->pixelformat) {	default:	case V4L2_PIX_FMT_RGB565:		pfmt = RGB565;		break;	case V4L2_PIX_FMT_UYVY:		pfmt = YUV422;		break;	}	dev_dbg(&sensor->i2c_client->dev,		"configuring pixel format %d\n", pfmt);	val = tcm825x_fmt_reg[pfmt]->val;	err = tcm825x_write_reg_mask(sensor->i2c_client,				     tcm825x_fmt_reg[pfmt]->reg, val);	if (err)		return err;	/*	 * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be	 * set. Frame rate will be halved from the normal.	 */	tgt_fps = fper->denominator / fper->numerator;	if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {		val = tcm825x_read_reg(sensor->i2c_client, 0x02);		val |= 0x80;		tcm825x_write_reg(sensor->i2c_client, 0x02, val);	}	return 0;}static int ioctl_queryctrl(struct v4l2_int_device *s,				struct v4l2_queryctrl *qc){	struct vcontrol *control;

⌨️ 快捷键说明

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