/*
* 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_FPS
struct 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