
/*===   file include        ===*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/videodev2.h>

#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-common.h>

#include <media/tvp5158.h>
#include "tvp5158_regs.h"

/*===   SECTION NAME        ===*/

/*===   user definition     ===*/
/* Module Name */
#define TVP5158_MODULE_NAME	"tvp5158"

/* I2C retry attempts */
#define I2C_RETRY_COUNT		(5)

/* End of registers */
#define TVP5158_EOR		0xff

/* Private macros for TVP */
#define LOCK_RETRY_COUNT    (5)
#define LOCK_RETRY_DELAY    (200)


/* Read write definition for registers */
#define TVP5158_READ		0
#define TVP5158_WRITE		1
#define TVP5158_RESERVED	2



/*===   external variable   ===*/

/*===   external function   ===*/

/*===   public function prototypes  ===*/

/*===   static function prototypes  ===*/


/*===   static typedef variable     ===*/

/*===   static variable     ===*/
/* Debug functions */
static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");

MODULE_AUTHOR("HidekiYamada <hideki.yamada@palgiken.co.jp>");
MODULE_DESCRIPTION("TVP5158 linux decoder driver");
MODULE_LICENSE("GPL");

/* Structure for register values */
struct i2c_reg_value {
	u8 reg;
	u8 value;
	u8 type;
};

/* Preset definition for handling device operation */
struct tvp5158_preset_definition {                                              // ���e�킩���Ȃ�
	char name[50];
	u32 preset;
	const struct i2c_reg_value *p_settings;
	enum v4l2_colorspace color_space;
	enum v4l2_field scanmode;
	u16 progressive;
	u16 lines_per_frame;
	u16 cpl_min;
	u16 cpl_max;
};

/*===   constant variable   ===*/
/*
 * Register default values (according to tvp5158 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 tvp5158_init_default[] = {
	{ VPS_TVP5158_REG_VID_STD_SELECT,	0x01, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AUTO_SW_MASK,		0xff, TVP5158_WRITE },
	{ VPS_TVP5158_REG_Y_BRIGHTNESS,		0x80, TVP5158_WRITE },
	{ VPS_TVP5158_REG_Y_CONTRAST,		0x80, TVP5158_WRITE },
	{ VPS_TVP5158_REG_C_SATURATION,		0x80, TVP5158_WRITE },
	{ VPS_TVP5158_REG_C_HUE,			0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_Y_CTRL_1,			0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_Y_CTRL_2,			0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_C_CTRL_1,			0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_C_CTRL_2,			0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_VID_STD_STATUS,	0x81, TVP5158_WRITE },
	{ VPS_TVP5158_REG_NR_MAX_NOISE,		0x28, TVP5158_WRITE },
	{ VPS_TVP5158_REG_NR_CTRL,			0x09, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OP_MODE_CTRL,		0x08, TVP5158_WRITE },
	{ VPS_TVP5158_REG_FV_DEC_CTRL,		0x03, TVP5158_WRITE },
	{ VPS_TVP5158_REG_FV_CTRL,			0x06, TVP5158_WRITE },
//	{ 0x90,								0xEB, TVP5158_WRITE },	// White
//	{ 0x91,								0x80, TVP5158_WRITE },	// White
//	{ 0x92,								0x80, TVP5158_WRITE },	// White
//	{ 0x93,								0x00, TVP5158_WRITE },	// White
//	{ 0x90,								0x51, TVP5158_WRITE },	// Red
//	{ 0x91,								0x5A, TVP5158_WRITE },	// Red
//	{ 0x92,								0xF0, TVP5158_WRITE },	// Red
//	{ 0x93,								0x00, TVP5158_WRITE },	// Red
	{ 0x90,								0x91, TVP5158_WRITE },	// Green
	{ 0x91,								0x36, TVP5158_WRITE },	// Green
	{ 0x92,								0x22, TVP5158_WRITE },	// Green
	{ 0x93,								0x00, TVP5158_WRITE },	// Green
//	{ 0x90,								0xD2, TVP5158_WRITE },	// Yellow
//	{ 0x91,								0x10, TVP5158_WRITE },	// Yellow
//	{ 0x92,								0x92, TVP5158_WRITE },	// Yellow
//	{ 0x93,								0x00, TVP5158_WRITE },	// Yellow
	{ 0xA9,								0x04, TVP5158_WRITE },	// FORCE
	{ VPS_TVP5158_REG_ESYNC_OFFSET_1,	0x02, TVP5158_WRITE },
	{ VPS_TVP5158_REG_ESYNC_OFFSET_2,	0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1,	0x20, TVP5158_WRITE },	// SINGLE_CH_NON_MUX_EMBEDDED_SNYC 1ch non-interleave 
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2,	0x11, TVP5158_WRITE },	// SINGLE_CH_NON_MUX_EMBEDDED_SNYC video-ded-enable chanid-desenable
//	{ VPS_TVP5158_REG_OFM_CH_SEL_1,		0xE9, TVP5158_WRITE },  // change ch0 <-> ch1
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,	0x30, TVP5158_WRITE }, 
	{ VPS_TVP5158_REG_AUDIO_SAMPLE_HZ,	0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AUDIO_GAIN_1,		0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AUDIO_GAIN_2,		0x00, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AUDIO_MIXER,		0x01, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AUDIO_CASCADE,	0x00, TVP5158_WRITE },
	{ 0x24,								0x01, TVP5158_WRITE },
/* This signals end of register values */
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};

/* Register parameters for 480P */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_480P[] = {
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x20, TVP5158_WRITE },
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2,	0x11, TVP5158_WRITE },	// 
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },	// portb-enable outclockp-enable OSC-enable
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
#if 0
/* Register parameters for 576P */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_576P[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x40, TVP5158_WRITE },
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2, 	0x11, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
/* Register parameters for 1080I60 */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_1080I60[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x20, TVP5158_WRITE },
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2, 	0x11, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
/* Register parameters for 1080P60 */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_1080P60[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x2q0, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2,	0x11, TVP5158_WRITE },	// 
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
/* Register parameters for 1080I50 */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_1080I50[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x40, TVP5158_WRITE },
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2, 	0x11, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
/* Register parameters for 720P60 */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_720P60[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x40, TVP5158_WRITE },
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2, 	0x11, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
/* Register parameters for 720P50 */	/* D1 out put pal uchinoura     */
static const struct i2c_reg_value tvp5158_parms_720P50[] = {
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x40, TVP5158_WRITE },
//	{ VPS_TVP5158_REG_AVD_OUT_CTRL_1, 	0x00, TVP5158_WRITE },	// non-interleaved mode 1chD1
	{ VPS_TVP5158_REG_AVD_OUT_CTRL_2, 	0x11, TVP5158_WRITE },
	{ VPS_TVP5158_REG_OFM_MODE_CTRL,  	0x25, TVP5158_WRITE },
	{ TVP5158_EOR, 						0xff, TVP5158_RESERVED }
};
#endif

/* Struct list for digital video presets */

#if 0

//#define		V4L2_DV_INVALID		0
//#define		V4L2_DV_480P59_94	1 /* BT.1362 */
//#define		V4L2_DV_576P50		2 /* BT.1362 */
//#define		V4L2_DV_720P24		3 /* SMPTE 296M */
//#define		V4L2_DV_720P25		4 /* SMPTE 296M */
//#define		V4L2_DV_720P30		5 /* SMPTE 296M */
//#define		V4L2_DV_720P50		6 /* SMPTE 296M */
//#define		V4L2_DV_720P59_94	7 /* SMPTE 274M */
//#define		V4L2_DV_720P60		8 /* SMPTE 274M/296M */
//#define		V4L2_DV_1080I29_97	9 /* BT.1120/ SMPTE 274M */
//#define		V4L2_DV_1080I30		10 /* BT.1120/ SMPTE 274M */
//#define		V4L2_DV_1080I25		11 /* BT.1120 */
//#define		V4L2_DV_1080I50		12 /* SMPTE 296M */
//#define		V4L2_DV_1080I60		13 /* SMPTE 296M */
//#define		V4L2_DV_1080P24		14 /* SMPTE 296M */
//#define		V4L2_DV_1080P25		15 /* SMPTE 296M */
//#define		V4L2_DV_1080P30		16 /* SMPTE 296M */
//#define		V4L2_DV_1080P50		17 /* BT.1120 */

//#define		V4L2_DV_1080P60		18 /* BT.1120 */  
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */

enum v4l2_colorspace {
	/* ITU-R 601 -- broadcast NTSC/PAL */
	V4L2_COLORSPACE_SMPTE170M     = 1,

	/* 1125-Line (US) HDTV */
	V4L2_COLORSPACE_SMPTE240M     = 2,

	/* HD and modern captures. */
	V4L2_COLORSPACE_REC709        = 3,

	/* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
	V4L2_COLORSPACE_BT878         = 4,

	/* These should be useful.  Assume 601 extents. */
	V4L2_COLORSPACE_470_SYSTEM_M  = 5,
	V4L2_COLORSPACE_470_SYSTEM_BG = 6,

	/* I know there will be cameras that send this.  So, this is
	 * unspecified chromaticities and full 0-255 on each of the
	 * Y'CbCr components
	 */
	V4L2_COLORSPACE_JPEG          = 7,

	/* For RGB colourspaces, this is probably a good start. */
	V4L2_COLORSPACE_SRGB          = 8,
};
enum v4l2_field {
	V4L2_FIELD_ANY           = 0, /* driver can choose from none,
					 top, bottom, interlaced
					 depending on whatever it thinks
					 is approximate ... */
	V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
	V4L2_FIELD_TOP           = 2, /* top field only */
	V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
	V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
	V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
					 buffer, top-bottom order */
	V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
	V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
					 separate buffers */
	V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
					 first and the top field is
					 transmitted first */
	V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
					 first and the bottom field is
					 transmitted first */
};
#endif
static const struct tvp5158_preset_definition tvp5158_presets[] = {             // ���e�킩���Ȃ�
#if 0
	{
		"V4L2_DV_720P60",
		V4L2_DV_720P60,
//		tvp5158_parms_1080P60,
		tvp5158_parms_720P60,
		V4L2_COLORSPACE_REC709,
		V4L2_FIELD_NONE,
		0,
		0x2EE,
		135,
		153
	},
	{
		"V4L2_DV_1080I60",
		V4L2_DV_1080I60,
//		tvp5158_parms_1080P60,
		tvp5158_parms_1080I60,
		V4L2_COLORSPACE_REC709,
		V4L2_FIELD_INTERLACED,
		0,
		0x465,
		181,
		205
	},
	{
		"V4L2_DV_1080I50",
		V4L2_DV_1080I50,
//		tvp5158_parms_1080P60,
		tvp5158_parms_1080I50,
		V4L2_COLORSPACE_REC709,
		V4L2_FIELD_INTERLACED,
		0,
		0x465,
		217,
		245
	},
	{
		"V4L2_DV_720P50",
		V4L2_DV_720P50,
//		tvp5158_parms_1080P60,
		tvp5158_parms_720P50,
		V4L2_COLORSPACE_REC709,
		V4L2_FIELD_NONE,
		1,
		0x2EE,
		163,
		183
	},
	{
		"V4L2_DV_1080P60",
		V4L2_DV_1080P60,
		tvp5158_parms_1080P60,
		V4L2_COLORSPACE_REC709,
		V4L2_FIELD_NONE,
		1,
		0x465,
		90,
		102
	},
#endif
	{
		"V4L2_DV_480P59_94",
		V4L2_DV_480P59_94,
		tvp5158_parms_480P,
		V4L2_COLORSPACE_SMPTE170M,
//		V4L2_FIELD_NONE,
		V4L2_FIELD_INTERLACED,
//		1,
		0,	// interlace
		0x20D,
		0xffff,
		0xffff
	},
	{
		"V4L2_DV_1080I60",
		V4L2_DV_1080I60,
		tvp5158_parms_480P,
		V4L2_COLORSPACE_SMPTE170M,
		V4L2_FIELD_INTERLACED,
		0,	// interlace
		0x20D,
		0xffff,
		0xffff
	},
#if 0
	{
		"V4L2_DV_576P50",
		V4L2_DV_576P50,
		tvp5158_parms_576P,
		V4L2_COLORSPACE_SMPTE170M,
		V4L2_FIELD_NONE,
		1,
		0x271,
		0xffff,
		0xffff
	}
#endif
};

#define NUM_PRESETS	ARRAY_SIZE(tvp5158_presets)

/*===   global variable     ===*/


/*===   implementation      ===*/


/* Device definition */
struct tvp5158 {
	struct v4l2_subdev sd;
	const struct tvp5158_config *pdata;

	int ver;
	int streaming;

	const struct tvp5158_preset_definition *current_preset;
	u8 gain;
};

/*
 * to_tvp5158 - Obtain device handler TVP5158
 * @sd: ptr to v4l2_subdev struct
 *
 * Returns device handler tvp5158.
 */
static inline struct tvp5158 *to_tvp5158(struct v4l2_subdev *sd)
{
	return container_of(sd, struct tvp5158, sd);
}

/*
 * tvp5158_read - Read a value from a register in an TVP5158
 * @sd: ptr to v4l2_subdev struct
 * @addr: TVP5158 register address
 * @dst: pointer to 8-bit destination
 *
 * Returns value read if successful, or non-zero (-1) otherwise.
 */
static int tvp5158_read(struct v4l2_subdev *sd, u8 addr, u8 *dst)
{
	struct i2c_client *c = v4l2_get_subdevdata(sd);
	int retry;
	int error;

	for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
		error = i2c_smbus_read_byte_data(c, addr);

		if (error >= 0) {
			*dst = (u8)error;
			return 0;
		}

		msleep_interruptible(10);
	}
	v4l2_err(sd, "TVP5158 read error %d\n", error);
	return error;
}

/*
 * tvp5158_read_err() - Read a register value with error code
 * @sd: pointer to standard V4L2 sub-device structure
 * @reg: destination register
 * @val: value to be read
 * @err: pointer to error value
 *
 * Read a value in a register and save error value in pointer.
 * Also update the register table if successful
 */
static inline void tvp5158_read_err(struct v4l2_subdev *sd, u8 reg,
							u8 *dst, int *err)
{
	if (!*err)
		*err = tvp5158_read(sd, reg, dst);
}

/*
 * tvp5158_write() - Write a value to a register in TVP5158
 * @sd: ptr to v4l2_subdev struct
 * @addr: TVP5158 register address
 * @value: value to be written to the register
 *
 * Write a value to a register in an TVP5158 decoder device.
 * Returns zero if successful, or non-zero otherwise.
 */
static int tvp5158_write(struct v4l2_subdev *sd, u8 addr, u8 value)
{
	struct i2c_client *c;
	int retry;
	int error;

	c = v4l2_get_subdevdata(sd);

	for (retry = 0; retry < I2C_RETRY_COUNT; retry++) {
		error = i2c_smbus_write_byte_data(c, addr, value);

		if (error >= 0)
			return 0;

		v4l2_warn(sd, "Write: retry ... %d\n", retry);
		msleep_interruptible(10);
	}
	v4l2_err(sd, "TVP5158 write error %d\n", error);
	return error;
}

/*
 * tvp5158_write_err() - Write a register value with error code
 * @sd: pointer to standard V4L2 sub-device structure
 * @reg: destination register
 * @val: value to be written
 * @err: pointer to error value
 *
 * Write a value in a register and save error value in pointer.
 * Also update the register table if successful
 */
static inline void tvp5158_write_err(struct v4l2_subdev *sd, u8 reg,
							u8 val, int *err)
{
	if (!*err)
		*err = tvp5158_write(sd, reg, val);
}

/*
 * tvp5158_g_chip_ident() - Get chip identification number
 * @sd: ptr to v4l2_subdev struct
 * @chip: ptr to v4l2_dbg_chip_ident struct
 *
 * Obtains the chip's identification number.
 * Returns zero or -EINVAL if read operation fails.
 */

#if 1 // pal uchinoura
static void reg_dump(struct v4l2_subdev *sd, int st, int len)
{
	int i;
	unsigned char dat;

	printk("reg dump-------------------------------------------\n");
	for (i=0; i<len; i++) {
		if (i%16 == 0) printk("%02X:", i);
		tvp5158_read(sd, i, &dat);
		printk("%02X ", dat);
		if ((i+1)%16 == 0) printk("\n");
	}
}
#endif

static int tvp5158_g_chip_ident(struct v4l2_subdev *sd,
					struct v4l2_dbg_chip_ident *chip)
{
	u8      rev[2]={0};
    u32     chipid;
	int     error;
	struct  i2c_client *client = v4l2_get_subdevdata(sd);

	error = tvp5158_read(sd, VPS_TVP5158_REG_CHIP_ID_MSB, &rev[0]);                           // TVP5158_CHIP_REV ����
	if (error < 0)
		return error;
	error = tvp5158_read(sd, VPS_TVP5158_REG_CHIP_ID_LSB, &rev[1]);                           // TVP5158_CHIP_REV ����
	if (error < 0)
		return error;
        
    chipid = ((u32)rev[0]<<8) | rev[1];
	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5158, chipid);   // v4l2-chip-ident.h �� V4L2_IDENT_TVP5158=5158 �ǉ�
}

/*
 * tvp5158_write_inittab() - Write initialization values
 * @sd: ptr to v4l2_subdev struct
 * @regs: ptr to i2c_reg_value struct
 *
 * Write initialization values.
 * Returns zero or -EINVAL if read operation fails.
 */
static int tvp5158_write_inittab(struct v4l2_subdev *sd,
					const struct i2c_reg_value *regs)
{
	int error = 0;
	int error2 = 0;
	u8	rev;

	/* Initialize the first (defined) registers */
	while (TVP5158_EOR != regs->reg) {
		if (TVP5158_WRITE == regs->type)
			tvp5158_write_err(sd, regs->reg, regs->value, &error);
		rev=0;
		tvp5158_read_err(sd, regs->reg, &rev, &error2);                           // TVP5158_CHIP_REV ����
		regs++;
	}

	return error;
}

/*
 * tvp5158_s_dv_preset() - Set digital video preset
 * @sd: ptr to v4l2_subdev struct
 * @dv_preset: ptr to v4l2_dv_preset struct
 *
 * Set the digital video preset for a TVP5158 decoder device.
 * Returns zero when successful or -EINVAL if register access fails.
 */
 
                                                                                // �Ȃɂ�邩�킩���Ȃ��I�I
static int tvp5158_s_dv_preset(struct v4l2_subdev *sd,
					struct v4l2_dv_preset *dv_preset)
{
	struct tvp5158 *device = to_tvp5158(sd);
	u32 preset;
	int i;
	int	err;
	unsigned char v_line_status[2];

	v4l2_info(sd, "pass %s(%d)\n", __func__, __LINE__);
	for (i = 0; i < NUM_PRESETS; i++) {
		preset = tvp5158_presets[i].preset;
		v4l2_info(sd, "-preset[%d] ------------------------------\n", i);
		v4l2_info(sd, "preset         = %s\n", 	tvp5158_presets[i].name);
		v4l2_info(sd, "reg=0x%X val=0x%X\n", 	tvp5158_presets[i].p_settings->reg, tvp5158_presets[i].p_settings->value);
		v4l2_info(sd, "color_space    = %d\n", 	tvp5158_presets[i].color_space);
		v4l2_info(sd, "scanmode       = %d\n", 	tvp5158_presets[i].scanmode);
		v4l2_info(sd, "progressive    = %d\n", 	tvp5158_presets[i].progressive);
		v4l2_info(sd, "lines_per_frame= %d\n", 	tvp5158_presets[i].lines_per_frame);
		v4l2_info(sd, "cpl_min        = %d\n", 	tvp5158_presets[i].cpl_min);
		v4l2_info(sd, "cpl_max        = %d\n", 	tvp5158_presets[i].cpl_max);
	}
	for (i = 0; i < NUM_PRESETS; i++) {
		preset = tvp5158_presets[i].preset;
		if (preset == dv_preset->preset) {
			device->current_preset = &tvp5158_presets[i];
			v4l2_info(sd, "-selected preset[%d] ------------------------------\n", i);
			v4l2_info(sd, "preset         = %s\n", device->current_preset->name);
			v4l2_info(sd, "reg=0x%X val=0x%X\n",  device->current_preset->p_settings->reg, device->current_preset->p_settings->value);
			v4l2_info(sd, "color_space    = %d\n", device->current_preset->color_space);
			v4l2_info(sd, "scanmode       = %d\n", device->current_preset->scanmode);
			v4l2_info(sd, "progressive    = %d\n", device->current_preset->progressive);
			v4l2_info(sd, "lines_per_frame= %d\n", device->current_preset->lines_per_frame);
			v4l2_info(sd, "cpl_min        = %d\n", device->current_preset->cpl_min);
			v4l2_info(sd, "cpl_max        = %d\n", device->current_preset->cpl_max);
			
			err = tvp5158_write_inittab(sd, tvp5158_presets[i].p_settings);
			tvp5158_read(sd, 0xA2, &v_line_status[0]);
			tvp5158_read(sd, 0xA3, &v_line_status[1]);
			v4l2_info(sd, "v_line_status:%02X%02X\n", v_line_status[1], v_line_status[0]);

			reg_dump(sd, 0, 256);

			return err;
		}
	}

	return -EINVAL;
}

/*
 * tvp5158_g_ctrl() - Get a control
 * @sd: ptr to v4l2_subdev struct
 * @ctrl: ptr to v4l2_control struct
 *
 * Get a control for a TVP5158 decoder device.
 * Returns zero when successful or -EINVAL if register access fails.
 */
static int tvp5158_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct tvp5158 *device = to_tvp5158(sd);

	switch (ctrl->id) {
	case V4L2_CID_GAIN:                                                         // videodev2.h
		ctrl->value = device->gain;
		return 0;
	default:
		return -EINVAL;
	}
}

/*
 * tvp5158_s_ctrl() - Set a control
 * @sd: ptr to v4l2_subdev struct
 * @ctrl: ptr to v4l2_control struct
 *
 * Set a control in TVP5158 decoder device.
 * Returns zero when successful or -EINVAL if register access fails.
 */
static int tvp5158_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct tvp5158 *device = to_tvp5158(sd);
	int error = 0;

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
#if 0
		tvp5158_write_err(sd, TVP5158_R_FINE_GAIN,                              // ��ۂ̃p�����[�^�ɒu��������
						ctrl->value & 0xff, &error);
		tvp5158_write_err(sd, TVP5158_G_FINE_GAIN,
						ctrl->value & 0xff, &error);
		tvp5158_write_err(sd, TVP5158_B_FINE_GAIN,
						ctrl->value & 0xff, &error);
#endif
		if (error < 0)
			return error;

		/* Set only after knowing there is no error */
		device->gain = ctrl->value & 0xff;
		return 0;
	default:
		return -EINVAL;
	}
}

/*
 * tvp5158_queryctrl() - Query a control
 * @sd: ptr to v4l2_subdev struct
 * @qc: ptr to v4l2_queryctrl struct
 *
 * Query a control of a TVP5158 decoder device.
 * Returns zero when successful or -EINVAL if register read fails.
 */
static int tvp5158_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
	switch (qc->id) {
	case V4L2_CID_GAIN:
		/*
		 * Gain is supported [0-255, default=0, step=1]
		 */
		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
	default:
		return -EINVAL;
	}
}

/*
 * tvp5158_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt
 * @sd: pointer to standard V4L2 sub-device structure
 * @f: pointer to mediabus format structure
 *
 * Negotiate the image capture size and mediabus format.
 * There is only one possible format, so this single function works for
 * get, set and try.
 */
static int tvp5158_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
	struct tvp5158 *device = to_tvp5158(sd);
	struct v4l2_dv_enum_preset e_preset;
	int error;

	v4l2_info(sd, "pass %s(%d)\n", __func__, __LINE__);

	/* Calculate height and width based on current standard */
	error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
	if (error)
		return error;

	f->width    = e_preset.width;
	f->height   = e_preset.height;
#if 1
	f->code     = V4L2_MBUS_FMT_UYVY8_2X8;
	f->field    = V4L2_FIELD_INTERLACED;
	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
//	f->field    = device->current_preset->scanmode;
//	f->colorspace = device->current_preset->color_space;
#else
	f->code     = V4L2_MBUS_FMT_YUYV10_1X20;
	f->field    = device->current_preset->scanmode;
	f->colorspace = device->current_preset->color_space;
#endif
//	v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d, Code - %d, Field - %d, ColorSpace - %d",
//			f->width, f->height, f->code, f->field, f->colorspace);
	v4l2_info(sd, "MBUS_FMT: Width - %d, Height - %d, Code - %d, Field - %d, ColorSpace - %d",
			f->width, f->height, f->code, f->field, f->colorspace);
	return 0;
}

/*
 * tvp5158_query_dv_preset() - query DV preset
 * @sd: pointer to standard V4L2 sub-device structure
 * @qpreset: standard V4L2 v4l2_dv_preset structure
 *
 * Returns the current DV preset by TVP5158. If no active input is
 * detected, returns -EINVAL
 */
static int tvp5158_query_dv_preset(struct v4l2_subdev *sd,
						struct v4l2_dv_preset *qpreset)
{
	const struct tvp5158_preset_definition *presets = tvp5158_presets;
	struct  tvp5158 *device;
	u8      progressive;
	u32     lpfr;
	u32     cpln;
	int     error = 0;
	u8      lpf_lsb;
	u8      lpf_msb;
	u8      cpl_lsb;
	u8      cpl_msb;
	int     index;

	v4l2_info(sd, "pass %s(%d)\n", __func__, __LINE__);

	device = to_tvp5158(sd);

#if 0
#endif
#if 1	/* �����I��preset 0�ɂ���	uchinoura	*/
// 1080P-60
//	lpfr = 0x465;
//	cpln = 98;
//	progressive = 1;

// 1080I-60
//	lpfr = 0x465;
//	cpln = 198;
//	progressive = 0;

// 480P
//	lpfr = 0x20D;
//	cpln = 0xFFFF;
//	progressive = 1;
	error = tvp5158_read(sd, 0xA2, &lpf_lsb);
	if (error < 0){
	}
	error = tvp5158_read(sd, 0xA3, &lpf_msb);
	if (error < 0){
	}
	lpfr = lpf_msb<<8 | lpf_lsb;
	v4l2_info(sd, "current lines_per_frame=%d 		%s(%d)\n", lpfr, __func__, __LINE__);
	
#endif
	/* Do checking of video modes */
v4l2_info(sd, "[pal] NUM_PRESETS:%d\n", NUM_PRESETS);
#if 0
	for (index = 0; index < NUM_PRESETS; index++, presets++){
		v4l2_info(sd, "presets->lines_per_frame=%d %s(%d)\n", presets->lines_per_frame, __func__, __LINE__);
		v4l2_info(sd, "[pal] idx%d lpfr:%d prg:%d min:%d max:%d\n", index, presets->lines_per_frame, presets->progressive, presets->cpl_min, presets->cpl_max);
		if (lpfr  == presets->lines_per_frame &&
			progressive == presets->progressive) {
			if (presets->cpl_min == 0xffff)
				break;
			if (cpln >= presets->cpl_min && cpln <= presets->cpl_max)
				break;
		}
	}
	if (index == NUM_PRESETS) {
		v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
								lpfr, cpln);
		/* Could not detect a signal, so return the 'invalid' preset */
		qpreset->preset = V4L2_DV_INVALID;
		return 0;
	}
#endif
	/* Set values in found preset */
//	qpreset->preset = presets->preset;
	qpreset->preset = V4L2_DV_480P59_94;	// 設定値固定 palgken 


	/* Update lines per frame and clocks per line info */
//	v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset);
	v4l2_dbg(1, debug, sd, "detected preset: %d\n", qpreset->preset);
	return 0;
}

#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
 * tvp5158_g_register() - Get the value of a register
 * @sd: ptr to v4l2_subdev struct
 * @reg: ptr to v4l2_dbg_register struct
 *
 * Get the value of a TVP5158 decoder device register.
 * Returns zero when successful, -EINVAL if register read fails or
 * access to I2C client fails, -EPERM if the call is not allowed
 * by diabled CAP_SYS_ADMIN.
 */
static int tvp5158_g_register(struct v4l2_subdev *sd,
						struct v4l2_dbg_register *reg)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	u8 val;
	int ret;

	v4l2_info(sd, "pass %s(%d)\n", __func__, __LINE__);

	if (!v4l2_chip_match_i2c_client(client, &reg->match))
		return -EINVAL;
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	ret = tvp5158_read(sd, reg->reg & 0xff, &val);
	reg->val = val;
	return ret;
}

/*
 * tvp5158_s_register() - set a control
 * @sd: ptr to v4l2_subdev struct
 * @reg: ptr to v4l2_dbg_register struct
 *
 * Get the value of a TVP5158 decoder device register.
 * Returns zero when successful, -EINVAL if register read fails or
 * -EPERM if call not allowed.
 */
static int tvp5158_s_register(struct v4l2_subdev *sd,
						struct v4l2_dbg_register *reg)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	v4l2_info(sd, "pass %s(%d)\n", __func__, __LINE__);

	if (!v4l2_chip_match_i2c_client(client, &reg->match))
		return -EINVAL;
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	return tvp5158_write(sd, reg->reg & 0xff, reg->val & 0xff);
}
#endif

/*
 * tvp5158_enum_mbus_fmt() - Enum supported mediabus formats
 * @sd: pointer to standard V4L2 sub-device structure
 * @index: format index
 * @code: pointer to mediabus format
 *
 * Enumerate supported mediabus formats.
 */

static int tvp5158_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
					enum v4l2_mbus_pixelcode *code)
{
	/* Check requested format index is within range */
	if (index)
		return -EINVAL;
//	*code = V4L2_MBUS_FMT_YUYV10_1X20;
	*code = V4L2_MBUS_FMT_UYVY8_2X8;
	return 0;
}

/*
 * tvp5158_s_stream() - V4L2 decoder i/f handler for s_stream
 * @sd: pointer to standard V4L2 sub-device structure
 * @enable: streaming enable or disable
 *
 * Sets streaming to enable or disable, if possible.
 */
static int tvp5158_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct tvp5158 *device = to_tvp5158(sd);
	int error = 0;

	if (device->streaming == enable)
		return 0;

	if (enable) {
		/* Set output state on (low impedance means stream on) */
//		error = tvp5158_write(sd, TVP5158_MISC_CTL_2, 0x00);                    // ��ۂ̃p�����[�^�ɒu��������
		device->streaming = enable;
	} else {
		/* Set output state off (high impedance means stream off) */            // ��ۂ̃p�����[�^�ɒu��������
//		error = tvp5158_write(sd, TVP5158_MISC_CTL_2, 0x03);
		if (error)
			v4l2_dbg(1, debug, sd, "Unable to stop streaming\n");

		device->streaming = enable;
	}

	return error;
}

/*
 * tvp5158_log_status() - Print information about register settings
 * @sd: ptr to v4l2_subdev struct
 *
 * Log register values of a TVP5158 decoder device.
 * Returns zero or -EINVAL if read operation fails.
 */
static int tvp5158_log_status(struct v4l2_subdev *sd)
{
	const struct tvp5158_preset_definition *presets = tvp5158_presets;
	struct tvp5158 *device = to_tvp5158(sd);
	struct v4l2_dv_enum_preset e_preset;
	struct v4l2_dv_preset detected;
	int i;

	detected.preset = V4L2_DV_INVALID;
	/* Find my current standard*/
	tvp5158_query_dv_preset(sd, &detected);

	/* Print standard related code values */
	for (i = 0; i < NUM_PRESETS; i++, presets++)
		if (presets->preset == detected.preset)
			break;

	if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset))
		return -EINVAL;

	v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name);
	v4l2_info(sd, "   Pixels per line: %u\n", e_preset.width);
	v4l2_info(sd, "   Lines per frame: %u\n\n", e_preset.height);
	if (i == NUM_PRESETS) {
		v4l2_info(sd, "Detected DV Preset: None\n");
	} else {
		if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
			return -EINVAL;
		v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name);
		v4l2_info(sd, "  Pixels per line: %u\n", e_preset.width);
		v4l2_info(sd, "  Lines per frame: %u\n\n", e_preset.height);
	}
	v4l2_info(sd, "Streaming enabled: %s\n",
					device->streaming ? "yes" : "no");

	/* Print the current value of the gain control */
	v4l2_info(sd, "Gain: %u\n", device->gain);

	return 0;
}

/*
 * tvp5158_enum_dv_presets() - Enum supported digital video formats
 * @sd: pointer to standard V4L2 sub-device structure
 * @preset: pointer to format struct
 *
 * Enumerate supported digital video formats.
 */
static int tvp5158_enum_dv_presets(struct v4l2_subdev *sd,
		struct v4l2_dv_enum_preset *preset)
{
	/* Check requested format index is within range */
	if (preset->index >= NUM_PRESETS)
		return -EINVAL;

	return v4l_fill_dv_preset_info(tvp5158_presets[preset->index].preset, preset);
}

/* V4L2 core operation handlers */
static const struct v4l2_subdev_core_ops tvp5158_core_ops = {
	.g_chip_ident   = tvp5158_g_chip_ident,
	.log_status     = tvp5158_log_status,
	.g_ctrl         = tvp5158_g_ctrl,
	.s_ctrl         = tvp5158_s_ctrl,
	.queryctrl      = tvp5158_queryctrl,
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.g_register     = tvp5158_g_register,
	.s_register     = tvp5158_s_register,
#endif
};

/* Specific video subsystem operation handlers */
static const struct v4l2_subdev_video_ops tvp5158_video_ops = {
	.enum_dv_presets= tvp5158_enum_dv_presets,
	.s_dv_preset    = tvp5158_s_dv_preset,
	.query_dv_preset= tvp5158_query_dv_preset,
	.s_stream       = tvp5158_s_stream,
	.g_mbus_fmt     = tvp5158_mbus_fmt,
	.try_mbus_fmt   = tvp5158_mbus_fmt,
	.s_mbus_fmt     = tvp5158_mbus_fmt,
	.enum_mbus_fmt  = tvp5158_enum_mbus_fmt,
};

/* V4L2 top level operation handlers */
static const struct v4l2_subdev_ops tvp5158_ops = {
	.core           = &tvp5158_core_ops,
	.video          = &tvp5158_video_ops,
};

static struct tvp5158 tvp5158_dev = {
	.streaming = 0,
	.current_preset = tvp5158_presets,
	.gain = 0,
};

/*
 * tvp5158_probe - Probe a TVP5158 device
 * @c: ptr to i2c_client struct
 * @id: ptr to i2c_device_id struct
 *
 * Initialize the TVP5158 device
 * Returns zero when successful, -EINVAL if register read fails or
 * -EIO if i2c access is not available.
 */
static int tvp5158_probe(struct i2c_client *c, const struct i2c_device_id *id)
{
	struct  v4l2_subdev *sd;
	struct  tvp5158 *device;
	struct  v4l2_dv_preset preset;
	int     polarity_a;
	int     polarity_b;
	u8      revision1;
	u8      revision2;

	int     error;

	/* Check if the adapter supports the needed features */
	if (!i2c_check_functionality(c->adapter,
		I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
		return -EIO;

	if (!c->dev.platform_data) {
		v4l_err(c, "No platform data!!\n");
		return -ENODEV;
	}

	device = kmalloc(sizeof(struct tvp5158), GFP_KERNEL);

	if (!device)
		return -ENOMEM;

	*device = tvp5158_dev;
	sd = &device->sd;
	device->pdata = c->dev.platform_data;

	/* Tell v4l2 the device is ready */
	v4l2_i2c_subdev_init(sd, c, &tvp5158_ops);
	v4l_info(c, "tvp5158 found @ 0x%02x (%s)\n",
					c->addr, c->adapter->name);

	error = tvp5158_read(sd, VPS_TVP5158_REG_CHIP_ID_MSB, &revision1);
	if (error < 0)
		goto found_error;
	error = tvp5158_read(sd, VPS_TVP5158_REG_CHIP_ID_LSB, &revision2);
	if (error < 0)
		goto found_error;

	/* Get revision number */
	v4l2_info(sd, "Rev. %02x%02X detected.\n", revision1, revision2);
	if ((revision1 != 0x51) || (revision2 != 0x58))
		v4l2_info(sd, "Unknown revision detected.\n");

	/* Initializes TVP5158 to its default values */
	error = tvp5158_write_inittab(sd, tvp5158_init_default);
	if (error < 0)
		goto found_error;

	/* Set polarity information after registers have been set */
	polarity_a = 0x20 | device->pdata->hs_polarity << 5
			| device->pdata->vs_polarity << 2;
//	error = tvp5158_write(sd, TVP5158_SYNC_CTL_1, polarity_a);                  // ��ۂ̃p�����[�^�̒u������
	if (error < 0)
		goto found_error;

	polarity_b = 0x01  | device->pdata->fid_polarity << 2
			| device->pdata->sog_polarity << 1
			| device->pdata->clk_polarity;
//	error = tvp5158_write(sd, TVP5158_MISC_CTL_3, polarity_b);                  // ��ۂ̃p�����[�^�̒u������
	if (error < 0)
		goto found_error;

	/* Set registers according to default video mode */
	preset.preset = device->current_preset->preset;
	v4l2_info(sd, "preset=%d\n", preset.preset);								// palgiken 120612
	error = tvp5158_s_dv_preset(sd, &preset);

found_error:
	if (error < 0)
		kfree(device);

	return error;
}

/*
 * tvp5158_remove - Remove TVP5158 device support
 * @c: ptr to i2c_client struct
 *
 * Reset the TVP5158 device
 * Returns zero.
 */
static int tvp5158_remove(struct i2c_client *c)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(c);
	struct tvp5158 *device = to_tvp5158(sd);

	v4l2_dbg(1, debug, sd, "Removing tvp5158 adapter"
				"on address 0x%x\n", c->addr);

	v4l2_device_unregister_subdev(sd);
	kfree(device);
	return 0;
}

/* I2C Device ID table */
static const struct i2c_device_id tvp5158_id[] = {
	{ "tvp5158", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, tvp5158_id);

/* I2C driver data */
static struct i2c_driver tvp5158_driver = {
	.driver = {
		.owner  = THIS_MODULE,
		.name   = TVP5158_MODULE_NAME,
	},
	.probe      = tvp5158_probe,
	.remove     = tvp5158_remove,
	.id_table   = tvp5158_id,
};

/*
 * tvp5158_init - Initialize driver via I2C interface
 *
 * Register the TVP5158 driver.
 * Return 0 on success or error code on failure.
 */
static int __init tvp5158_init(void)
{
	return i2c_add_driver(&tvp5158_driver);
}

/*
 * tvp5158_exit - Remove driver via I2C interface
 *
 * Unregister the TVP5158 driver.
 * Returns nothing.
 */
static void __exit tvp5158_exit(void)
{
	i2c_del_driver(&tvp5158_driver);
}

module_init(tvp5158_init);
module_exit(tvp5158_exit);
