/***************************************************************
* =============================================================
* file : input_module/tw9910.c
* brief : TechWell TW9910 capture Input module driver
* =============================================================
*
* Revision 0.1.0 2010/12/13 Jerson_Lin
* initial version
*
* Revision 0.1.1 2010/12/23 Jerson_Lin
* 1. fixed not free i2c resource problem when module remove.
*
* Revision 0.1.2 2011/01/14 Jerson_Lin
* 1. fixed i2c_new_device fail problem when insert two input module at the same time.
*
* Revision 0.2.0 2011/04/08 Jerson_Lin
* 1. modify for support GM818X and GM812X
*
***************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/videodev.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <asm/glue.h>
#include "input_type.h"
#include "dev_api.h"
#include "drv_api.h"
#include "drv_common.h"
#include "fcap_misc.h"
#include "proc.h"
#include "tw9910cmn.h"
#undef PFX
//-----User Modify-----
#define PFX "TW9910"
#define MODULE_NAME "max9526"
#include "debug.h"
#define DEFAULT_TYPE_CH0 FCAP_INPUT_TW9910COMPOSITE
#define DEFAULT_TYPE_CH1 FCAP_INPUT_TW9910SVIDEO
#define DEFAULT_NORM_WIDTH 720
#define DEFAULT_NORM_HEIGHT 480
#define DEFAULT_NORM_HEIGHT_PAL 576
#define DEFAULT_INTERLACE_BE_EVEN_FIRST 0
#define DEFAULT_DATA_RANGE 1
#define DEFAULT_INTERFACE VIF_IF(VIP_CCIR656, VIP_8BIT, VIP_INTERLACE)
#define DEVICE_TIMEOUT 80 /* 80 ms */
#define DEFAULT_I2C_CLOCKDIV 60
#define GMD 0
#define DEBUG_MAX 1
static u8 u8RegMax = 0x10;
extern int GM_i2c_xfer(struct i2c_msg *msgs,int num,int clockdiv);
/* Chip number selection */
static int chip_num = 1;
module_param(chip_num, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(chip_num, "Chip number");
static char *mode = "pal";
module_param(mode,charp,S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(mode,"Switch NTSC OR PAL");
#define uchar unsigned char
/* Chip I2C address */
static ushort yfiaddr = 0x42;
module_param(yfiaddr,ushort,S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(yfiaddr,"the max9526 i2c write slave address");
static ushort iaddr[2] = {0x8a,0x88};
#if 0
static ushort iaddr[2] = {0x8a, 0x88};
module_param_array(iaddr, short, NULL, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(iaddr, "i2c address");
#endif
/* VCAP Source selection */
static ushort src = 0;
module_param(src, ushort, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(src, "Capture source number");
/* Invert pixel clock selection */
static int inv_clk = 1;
module_param(inv_clk, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(inv_clk, "Invert pixel clock!");
/* Using bit V as frame start */
static int bUse_VFS = 0;
module_param(bUse_VFS, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(bUse_VFS, "Using bit V as frame start");
/* capture data output port selection, for GM818X */
static int port_used = -1;
module_param(port_used, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(port_used, "External signal connected with chip's port. BitX=PortX");
/* TW9910 output data frequence selection, for GM818X */
static ushort OData = 0; /* 27MHz */
module_param(OData, ushort, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(OData, "Output data frequence. 0:27MHz, 1:54MHz, 2:108MHz");
/* Invert DEMUX pixel clock selection, for GM818X */
#define DMUX_NUM 2
static int inv_demuxclk[DMUX_NUM] = {0, 0};
module_param_array(inv_demuxclk, int, NULL, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(inv_demuxclk, "Invert demux pixel clock!");
/* PMU external clock, for GM818X */
static int cfg_pmu_eclk = 0;
module_param(cfg_pmu_eclk, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(cfg_pmu_eclk, "Configure PMU external clock");
/* Config PMU DEMUX selection, for GM818X */
static int cfg_pmu_demux = -1;
module_param(cfg_pmu_demux, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(cfg_pmu_demux, "0:Demux0 1:Demux1 -1:Demux all");
/* channel switch, for GM818X */
static int cfg_channel_switch = 0;
module_param(cfg_channel_switch, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(cfg_channel_switch, "0: Disable, 1: Enable");
static input_info_t *channel0 = 0; /* Channel#0 for COMPOSITE */
static input_info_t *channel1 = 0; /* Channel#1 for SVIDEO */
static int channel0_run_mode[2] = {0, 0}; /* Channel#0 current run mode */
static int channel1_run_mode[2] = {0, 0}; /* Channel#1 current run mode */
//static uint i2c_init[2] = {0, 0}; /* bit0: NTSC COMPOSITE, bit1: PAL COMPOSITE, bit2: NTSC SVIDEO, bit3: PAL SVIDEO */
static demux_config_t demux_cfg = {0};
static int *TW9910_CHANNEL2PORT = NULL;
static uint i2c_init = 0;
DECLARE_MUTEX(i2c_lock);
/********************************************************************
* GM818X (Two TW9910 application)
* vcap channel and TW9910 Input Port Mapping Table
*
* port# TW9910# X_CAP# vcap#(channel) pixel clock
* 1 ------> 1 -----> 0 -------------o---> 0 27MHz
* 1 |
* 0 ------> 0 -----> 2 ---o---> 2 | 27MHz
* | 3 |
* | |---> 4 27MHz
* | 5
* |---> 6 27MHz
* 7
**********************************************************************/
static const int TW9910_CHANNEL2PORT_GM818X[] = {
/* VCAP0 */ 1, /* TW9910#1 */
/* VCAP1 */ -1,
/* VCAP2 */ 0, /* TW9910#0 */
/* VCAP3 */ -1,
/* VCAP4 */ 1, /* TW9910#1 */
/* VCAP5 */ -1,
/* VCAP6 */ 0, /* TW9910#0 */
/* VCAP7 */ -1
};
/********************************************************************
* GM812X (one TW9910 application)
* vcap channel and TW9910 Input Port Mapping Table
*
* port# TW9910# X_CAP# vcap#(channel) pixel clock
* 0 ------> 0 -----> 0 ---o--------> 0 27MHz
* |
* |--------> 1 27MHz
*
**********************************************************************/
static const int TW9910_CHANNEL2PORT_GM812X[] = {
/* VCAP0 */ 0, /* TW9910#0 */
/* VCAP1 */ 0, /* TW9910#0 */
};
/* TW9910
A11 = NO
A12 = NO
A21 = CVBS NTSC
A22 = NO
*/
#if 0
static char *max9526_cvbs_pal[] = {
"0x04 0x04",
"0x01 0x00",
"0x02 0x8C",
"0x03 0x00",
"0x05 0x80",
"0x06 0x00",
"0x07 0x80",
"0x08 0x88",
"0x09 0x02",
"0x0a 0x00",
"0x0b 0x2B",
"0x0c 0x00",
"0x0d 0x04",
"0x0e 0x03",
"0x0f 0x18",
"0x00 0x8C",
0
};
#endif
#if 1
static char *max9526_cvbs_pal[] = {
"0x0d 0x04",
// "0x02 0x00",
// "0x03 0x00",
// "0x04 0x10",
"0x05 0x88",
"0x06 0xf0",
"0x07 0x70",
"0x08 0xa0",
"0x09 0x02",
"0x0a 0xd0",
//"0x0d 0x04",
0
};
#endif
static char *TW9910_A21_CVBS_NTSC[] = {
"0x06 0x00",
"0x1a 0x4f",
"0x02 0x40", // S:54 CV:40
"0x03 0xa2",
"0x05 0x01",
"0x07 0x02",
"0x08 0x13",
"0x09 0xf2",
"0x0a 0x13",
"0x19 0x47",
"0x1a 0x0f",
"0x1b 0xc0",
"0x29 0x03",
"0x55 0x00",
"0x6b 0x26",
"0x6c 0x36",
"0x6d 0xF0",
"0x6e 0x28",
"0x1a 0x0f",
"0x06 0x80",
0
};
static char *TW9910_A21_CVBS_PAL[] = {
"0x06 0x00",
"0x1a 0x4f",
"0x02 0x40", // S:54 CV:40
"0x03 0xa2",
"0x05 0x01",
"0x07 0x12",
"0x08 0x19",
"0x09 0x22",
"0x0a 0x13",
"0x19 0x57",
"0x1a 0x0f",
"0x1b 0xc0",
"0x29 0x03",
"0x55 0x00",
"0x6b 0x26",
"0x6c 0x36",
"0x6d 0xF0",
"0x6e 0x38",
"0x1a 0x0f",
"0x06 0x80",
0
};
/* TW9910
A11 = NO
A12 = NO
A21 = NO
A22 = SVIDEO NTSC
*/
static char *TW9910_A22_SVIDEO_NTSC[] = {
"0x06 0x00",
"0x1a 0x4f",
"0x02 0x