/*
* Omnivision OV2659 CMOS Image Sensor driver
*
* Copyright (C) 2015 Texas Instruments, Inc.
*
* Benoit Parrot <bparrot@ti.com>
* Lad, Prabhakar <prabhakar.csengg@gmail.com>
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <media/media-entity.h>
#include <media/i2c/ov2659.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#define DRIVER_NAME "ov2659"
/*
* OV2659 register definitions
*/
#define REG_SOFTWARE_STANDBY 0x0100
#define REG_SOFTWARE_RESET 0x0103
#define REG_IO_CTRL00 0x3000
#define REG_IO_CTRL01 0x3001
#define REG_IO_CTRL02 0x3002
#define REG_OUTPUT_VALUE00 0x3008
#define REG_OUTPUT_VALUE01 0x3009
#define REG_OUTPUT_VALUE02 0x300d
#define REG_OUTPUT_SELECT00 0x300e
#define REG_OUTPUT_SELECT01 0x300f
#define REG_OUTPUT_SELECT02 0x3010
#define REG_OUTPUT_DRIVE 0x3011
#define REG_INPUT_READOUT00 0x302d
#define REG_INPUT_READOUT01 0x302e
#define REG_INPUT_READOUT02 0x302f
#define REG_SC_PLL_CTRL0 0x3003
#define REG_SC_PLL_CTRL1 0x3004
#define REG_SC_PLL_CTRL2 0x3005
#define REG_SC_PLL_CTRL3 0x3006
#define REG_SC_CHIP_ID_H 0x300a
#define REG_SC_CHIP_ID_L 0x300b
#define REG_SC_PWC 0x3014
#define REG_SC_CLKRST0 0x301a
#define REG_SC_CLKRST1 0x301b
#define REG_SC_CLKRST2 0x301c
#define REG_SC_CLKRST3 0x301d
#define REG_SC_SUB_ID 0x302a
#define REG_SC_SCCB_ID 0x302b
#define REG_GROUP_ADDRESS_00 0x3200
#define REG_GROUP_ADDRESS_01 0x3201
#define REG_GROUP_ADDRESS_02 0x3202
#define REG_GROUP_ADDRESS_03 0x3203
#define REG_GROUP_ACCESS 0x3208
#define REG_AWB_R_GAIN_H 0x3400
#define REG_AWB_R_GAIN_L 0x3401
#define REG_AWB_G_GAIN_H 0x3402
#define REG_AWB_G_GAIN_L 0x3403
#define REG_AWB_B_GAIN_H 0x3404
#define REG_AWB_B_GAIN_L 0x3405
#define REG_AWB_MANUAL_CONTROL 0x3406
#define REG_TIMING_HS_H 0x3800
#define REG_TIMING_HS_L 0x3801
#define REG_TIMING_VS_H 0x3802
#define REG_TIMING_VS_L 0x3803
#define REG_TIMING_HW_H 0x3804
#define REG_TIMING_HW_L 0x3805
#define REG_TIMING_VH_H 0x3806
#define REG_TIMING_VH_L 0x3807
#define REG_TIMING_DVPHO_H 0x3808
#define REG_TIMING_DVPHO_L 0x3809
#define REG_TIMING_DVPVO_H 0x380a
#define REG_TIMING_DVPVO_L 0x380b
#define REG_TIMING_HTS_H 0x380c
#define REG_TIMING_HTS_L 0x380d
#define REG_TIMING_VTS_H 0x380e
#define REG_TIMING_VTS_L 0x380f
#define REG_TIMING_HOFFS_H 0x3810
#define REG_TIMING_HOFFS_L 0x3811
#define REG_TIMING_VOFFS_H 0x3812
#define REG_TIMING_VOFFS_L 0x3813
#define REG_TIMING_XINC 0x3814
#define REG_TIMING_YINC 0x3815
#define REG_TIMING_VERT_FORMAT 0x3820
#define REG_TIMING_HORIZ_FORMAT 0x3821
#define REG_FORMAT_CTRL00 0x4300
#define REG_VFIFO_READ_START_H 0x4608
#define REG_VFIFO_READ_START_L 0x4609
#define REG_DVP_CTRL02 0x4708
#define REG_ISP_CTRL00 0x5000
#define REG_ISP_CTRL01 0x5001
#define REG_ISP_CTRL02 0x5002
#define REG_LENC_RED_X0_H 0x500c
#define REG_LENC_RED_X0_L 0x500d
#define REG_LENC_RED_Y0_H 0x500e
#define REG_LENC_RED_Y0_L 0x500f
#define REG_LENC_RED_A1 0x5010
#define REG_LENC_RED_B1 0x5011
#define REG_LENC_RED_A2_B2 0x5012
#define REG_LENC_GREEN_X0_H 0x5013
#define REG_LENC_GREEN_X0_L 0x5014
#define REG_LENC_GREEN_Y0_H 0x5015
#define REG_LENC_GREEN_Y0_L 0x5016
#define REG_LENC_GREEN_A1 0x5017
#define REG_LENC_GREEN_B1 0x5018
#define REG_LENC_GREEN_A2_B2 0x5019
#define REG_LENC_BLUE_X0_H 0x501a
#define REG_LENC_BLUE_X0_L 0x501b
#define REG_LENC_BLUE_Y0_H 0x501c
#define REG_LENC_BLUE_Y0_L 0x501d
#define REG_LENC_BLUE_A1 0x501e
#define REG_LENC_BLUE_B1 0x501f
#define REG_LENC_BLUE_A2_B2 0x5020
#define REG_AWB_CTRL00 0x5035
#define REG_AWB_CTRL01 0x5036
#define REG_AWB_CTRL02 0x5037
#define REG_AWB_CTRL03 0x5038
#define REG_AWB_CTRL04 0x5039
#define REG_AWB_LOCAL_LIMIT 0x503a
#define REG_AWB_CTRL12 0x5049
#define REG_AWB_CTRL13 0x504a
#define REG_AWB_CTRL14 0x504b
#define REG_SHARPENMT_THRESH1 0x5064
#define REG_SHARPENMT_THRESH2 0x5065
#define REG_SHARPENMT_OFFSET1 0x5066
#define REG_SHARPENMT_OFFSET2 0x5067
#define REG_DENOISE_THRESH1 0x5068
#define REG_DENOISE_THRESH2 0x5069
#define REG_DENOISE_OFFSET1 0x506a
#define REG_DENOISE_OFFSET2 0x506b
#define REG_SHARPEN_THRESH1 0x506c
#define REG_SHARPEN_THRESH2 0x506d
#define REG_CIP_CTRL00 0x506e
#define REG_CIP_CTRL01 0x506f
#define REG_CMX_SIGN 0x5079
#define REG_CMX_MISC_CTRL 0x507a
#define REG_PRE_ISP_CTRL00 0x50a0
#define TEST_PATTERN_ENABLE BIT(7)
#define VERTICAL_COLOR_BAR_MASK 0x53
#define REG_NULL 0x0000 /* Array end token */
#define OV265X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb))
#define OV2659_ID 0x2656
struct sensor_register {
u16 addr;
u8 value;
};
struct ov2659_framesize {
u16 width;
u16 height;
u16 max_exp_lines;
const struct sensor_register *regs;
};
struct ov2659_pll_ctrl {
u8 ctrl1;
u8 ctrl2;
u8 ctrl3;
};
struct ov2659_pixfmt {
u32 code;
/* Output format Register Value (REG_FORMAT_CTRL00) */
struct sensor_register *format_ctrl_regs;
};
struct pll_ctrl_reg {
unsigned int div;
unsigned char reg;
};
struct ov2659 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_mbus_framefmt format;
unsigned int xvclk_frequency;
const struct ov2659_platform_data *pdata;
struct mutex lock;
struct i2c_client *client;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *link_frequency;
const struct ov2659_framesize *frame_size;
struct sensor_register *format_ctrl_regs;
struct ov2659_pll_ctrl pll;
int streaming;
};
static const struct sensor_register ov2659_init_regs[] = {
{ REG_IO_CTRL00, 0x03 },
{ REG_IO_CTRL01, 0xff },
{ REG_IO_CTRL02, 0xe0 },
{ 0x3633, 0x3d },
{ 0x3620, 0x02 },
{ 0x3631, 0x11 },
{ 0x3612, 0x04 },
{ 0x3630, 0x20 },
{ 0x4702, 0x02 },
{ 0x370c, 0x34 },
{ REG_TIMING_HS_H, 0x00 },
{ REG_TIMING_HS_L, 0x00 },
{ REG_TIMING_VS_H, 0x00 },
{ REG_TIMING_VS_L, 0x00 },
{ REG_TIMING_HW_H, 0x06 },
{ REG_TIMING_HW_L, 0x5f },
{ REG_TIMING_VH_H, 0x04 },
{ REG_TIMING_VH_L, 0xb7 },
{ REG_TIMING_DVPHO_H, 0x03 },
{ REG_TIMING_DVPHO_L, 0x20 },
{ REG_TIMING_DVPVO_H, 0x02 },
{ REG_TIMING_DVPVO_L, 0x58 },
{ REG_TIMING_HTS_H, 0x05 },
{ REG_TIMING_HTS_L, 0x14 },
{ REG_TIMING_VTS_H, 0x02 },
{ REG_TIMING_VTS_L, 0x68 },
{ REG_TIMING_HOFFS_L, 0x08 }
|