// SPDX-License-Identifier: GPL-2.0-or-later
/* Texas Instruments Triple 8-/10-BIT 165-/110-MSPS Video and Graphics
* Digitizer with Horizontal PLL registers
*
* Copyright (C) 2009 Texas Instruments Inc
* Author: Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>
*
* This code is partially based upon the TVP5150 driver
* written by Mauro Carvalho Chehab <mchehab@kernel.org>,
* the TVP514x driver written by Vaibhav Hiremath <hvaibhav@ti.com>
* and the TVP7002 driver in the TI LSP 2.10.00.14. Revisions by
* Muralidharan Karicheri and Snehaprabha Narnakaje (TI).
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/v4l2-dv-timings.h>
#include <media/i2c/tvp7002.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include "tvp7002_reg.h"
MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
MODULE_AUTHOR("Santiago Nunez-Corrales <santiago.nunez@ridgerun.com>");
MODULE_LICENSE("GPL");
/* I2C retry attempts */
#define I2C_RETRY_COUNT (5)
/* End of registers */
#define TVP7002_EOR 0x5c
/* Read write definition for registers */
#define TVP7002_READ 0
#define TVP7002_WRITE 1
#define TVP7002_RESERVED 2
/* Interlaced vs progressive mask and shift */
#define TVP7002_IP_SHIFT 5
#define TVP7002_INPR_MASK (0x01 << TVP7002_IP_SHIFT)
/* Shift for CPL and LPF registers */
#define TVP7002_CL_SHIFT 8
#define TVP7002_CL_MASK 0x0f
/* Debug functions */
static bool debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* Structure for register values */
struct i2c_reg_value {
u8 reg;
u8 value;
u8 type;
};
/*
* Register default values (according to tvp7002 datasheet)
* In the case of read-only registers, the value (0xff) is
* never written. R/W functionality is controlled by the
* writable bit in the register struct definition.
*/
static const struct i2c_reg_value tvp7002_init_default[] = {
{ TVP7002_CHIP_REV, 0xff, TVP7002_READ },
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
{ TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x80, TVP7002_WRITE },
{ TVP7002_CLAMP_START, 0x32, TVP7002_WRITE },
{ TVP7002_CLAMP_W, 0x20, TVP7002_WRITE },
{ TVP7002_HSYNC_OUT_W, 0x60, TVP7002_WRITE },
{ TVP7002_B_FINE_GAIN, 0x00, TVP7002_WRITE },
{ TVP7002_G_FINE_GAIN, 0x00, TVP7002_WRITE },
{ TVP7002_R_FINE_GAIN, 0x00, TVP7002_WRITE },
{ TVP7002_B_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
{ TVP7002_G_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
{ TVP7002_R_FINE_OFF_MSBS, 0x80, TVP7002_WRITE },
{ TVP7002_SYNC_CTL_1, 0x20, TVP7002_WRITE },
{ TVP7002_HPLL_AND_CLAMP_CTL, 0x2e, TVP7002_WRITE },
{ TVP7002_SYNC_ON_G_THRS, 0x5d, TVP7002_WRITE },
{ TVP7002_SYNC_SEPARATOR_THRS, 0x47, TVP7002_WRITE },
{ TVP7002_HPLL_PRE_COAST, 0x00, TVP7002_WRITE },
{ TVP7002_HPLL_POST_COAST, 0x00, TVP7002_WRITE },
{ TVP7002_SYNC_DETECT_STAT, 0xff, TVP7002_READ },
{ TVP7002_OUT_FORMATTER, 0x47, TVP7002_WRITE },
{ TVP7002_MISC_CTL_1, 0x01, TVP7002_WRITE },
{ TVP7002_MISC_CTL_2, 0x00, TVP7002_WRITE },
{ TVP7002_MISC_CTL_3, 0x01, TVP7002_WRITE },
{ TVP7002_IN_MUX_SEL_1, 0x00, TVP7002_WRITE },
{ TVP7002_IN_MUX_SEL_2, 0x67, TVP7002_WRITE },
{ TVP7002_B_AND_G_COARSE_GAIN, 0x77, TVP7002_WRITE },
{ TVP7002_R_COARSE_GAIN, 0x07, TVP7002_WRITE },
{ TVP7002_FINE_OFF_LSBS, 0x00, TVP7002_WRITE },
{ TVP7002_B_COARSE_OFF, 0x10, TVP7002_WRITE },
{ TVP7002_G_COARSE_OFF, 0x10, TVP7002_WRITE },
{ TVP7002_R_COARSE_OFF, 0x10, TVP7002_WRITE },
{ TVP7002_HSOUT_OUT_START, 0x08, TVP7002_WRITE },
{ TVP7002_MISC_CTL_4, 0x00, TVP7002_WRITE },
{ TVP7002_B_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
{ TVP7002_G_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
{ TVP7002_R_DGTL_ALC_OUT_LSBS, 0xff, TVP7002_READ },
{ TVP7002_AUTO_LVL_CTL_ENABLE, 0x80, TVP7002_WRITE },
{ TVP7002_DGTL_ALC_OUT_MSBS, 0xff, TVP7002_READ },
{ TVP7002_AUTO_LVL_CTL_FILTER, 0x53, TVP7002_WRITE },
{ 0x29, 0x08, TVP7002_RESERVED },
{ TVP7002_FINE_CLAMP_CTL, 0x07, TVP7002_WRITE },
/* PWR_CTL is controlled only by the probe and reset functions */
{ TVP7002_PWR_CTL, 0x00, TVP7002_RESERVED },
{ TVP7002_ADC_SETUP, 0x50, TVP7002_WRITE },
{ TVP7002_COARSE_CLAMP_CTL, 0x00, TVP7002_WRITE },
{ TVP7002_SOG_CLAMP, 0x80, TVP7002_WRITE },
{ TVP7002_RGB_COARSE_CLAMP_CTL, 0x8c, TVP7002_WRITE },
{ TVP7002_SOG_COARSE_CLAMP_CTL, 0x04, TVP7002_WRITE },
{ TVP7002_ALC_PLACEMENT, 0x5a, TVP7002_WRITE },
{ 0x32, 0x18, TVP7002_RESERVED },
{ 0x33, 0x60, TVP7002_RESERVED },
{ TVP7002_MVIS_STRIPPER_W, 0xff, TVP7002_RESERVED },
{ TVP7002_VSYNC_ALGN, 0x10, TVP7002_WRITE },
{ TVP7002_SYNC_BYPASS, 0x00, TVP7002_WRITE },
{ TVP7002_L_FRAME_STAT_LSBS, 0xff, TVP7002_READ },
{ TVP7002_L_FRAME_STAT_MSBS, 0xff, TVP7002_READ },
{ TVP7002_CLK_L_STAT_LSBS, 0xff, TVP7002_READ },
{ TVP7002_CLK_L_STAT_MSBS, 0xff, TVP7002_READ },
{ TVP7002_HSYNC_W, 0xff, TVP7002_READ },
{ TVP7002_VSYNC_W, 0xff, TVP7002_READ },
{ TVP7002_L_LENGTH_TOL, 0x03, TVP7002_WRITE },
{ 0x3e, 0x60, TVP7002_RESERVED },
{ TVP7002_VIDEO_BWTH_CTL, 0x01, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x01, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_MSBS, 0x2c, TVP7002_WRITE },
{ TVP7002_AVID_STOP_PIXEL_LSBS, 0x06,