amlogic T972 的lt9211驱动
在t972上调试LVDS转rgb888驱动,基于T9211。有需要的朋友可以拿去参考。
1,设备树文件:
&i2c3 {
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c3_h20_pins>;
pinctrl-1 = <&i2c3_h20_pins_slp_input>;
clock-frequency = <100000>;
lt9211: lt9211@2d{
status = "okay";
compatible = "lt9211";
reg = <0x2d>;
};
};
2,驱动文件:
位置droid9/common/drivers/amlogic/media/vout/lcd/lcd_extern/i2c_lt9211.c
/*
*lt9211.c - Linux kernel modules for 9211
*2020.12.12 huanbin
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/input-polldev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/average.h>
#include <linux/kthread.h>
#include <linux/syscalls.h>
#include <../include/linux/gpio.h>
#include <linux/time.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#undef max_debug
#ifdef max_debug
#define lt9211_TAG "lt9211 "
#define lt9211_DEBUG(fmt, args...) printk(KERN_INFO lt9211_TAG fmt, ##args)
#else
#define lt9211_DEBUG(fmt, args...)
#endif
#define lt9211_I2C_NAME "lt9211"
#define INPUT_PORTA
#define INPUT_PORTB
#define _uart_debug_
#define INPUT_PORT_NUM 2
#define LVDS_FORMAT VESA_FORMAT
#define LVDS_MODE DE_MODE
/******************* Output Config ********************/
typedef enum LT9211_OUTPUTMODE_ENUM
{
OUTPUT_RGB888 = 0,
OUTPUT_BT656_8BIT = 1,
OUTPUT_BT1120_16BIT = 2,
OUTPUT_LVDS_2_PORT = 3,
OUTPUT_LVDS_1_PORT = 4,
OUTPUT_YCbCr444 = 5,
OUTPUT_YCbCr422_16BIT
}
_Video_Output_Mode;
#define LT9211_OutPutModde OUTPUT_RGB888
typedef enum VIDEO_INPUTMODE_ENUM
{
Input_RGB888,
Input_YCbCr444,
Input_YCbCr422_16BIT
}
_Video_Input_Mode;
#define Video_Input_Mode Input_RGB888
/*
typedef struct video_timing{
u16 hfp;
u16 hs;
u16 hbp;
u16 hact;
u16 htotal;
u16 vfp;
u16 vs;
u16 vbp;
u16 vact;
u16 vtotal;
u32 pclk_khz;
};
*/
int g_lt9211_flag;
u16 hact, vact, hs, vs, hbp, vbp, htotal, vtotal, hfp, vfp;
u32 lvds_clk_in = 0;
static int major;
static struct class *class;
struct lt9211_DATA
{
struct i2c_client *lt9211;
struct task_struct *attached_thread;
};
static struct i2c_client *i2c_connect_client1;
static int i2c_master_reg8_send (const struct i2c_client *client, const char reg,
const char *buf, int count)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msg;
int ret;
char *tx_buf = (char *) kzalloc (count + 1, GFP_KERNEL);
if (!tx_buf)
return -ENOMEM;
tx_buf[0] = reg;
memcpy (tx_buf + 1, buf, count);
msg.addr = client->addr;
msg.flags = client->flags;
msg.len = count + 1;
msg.buf = (char *) tx_buf;
ret = i2c_transfer (adap, &msg, 1);
if (ret < 0)
{
dev_warn(&client->dev,"i2c write failed(hb) ret= %d [addr 0x%02x] [reg 0x%02x][dat 0x%02x]\n", ret, client->addr, reg, buf[0]);
}
kfree (tx_buf);
return (ret == 1) ? count : ret;
}
static int i2c_master_reg8_recv (const struct i2c_client *client, const char reg,
char *buf, int count)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_msg msgs[2];
int ret;
buf[0] = reg;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].buf = (char *) buf;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = count;
msgs[1].buf = (char *) buf;
ret = i2c_transfer (adap, msgs, 2);
if (ret < 0)
{
dev_warn(&client->dev,"i2c read failed(hb) ret= %d [addr 0x%02x] [reg 0x%02x][dat 0x%02x]\n", ret, client->addr, reg, buf[0]);
}
return (ret == 2) ? count : ret;
}
static int
lt9211_i2c_set_reg (struct i2c_client *client, u8 reg, u8 const buf[],
__u16 len)
{
int ret;
ret = i2c_master_reg8_send (client, reg, buf, (int) len);
return ret;
}
static int HDMI_WriteI2C_Byte(u8 reg, u8 dat)
{
int ret;
u8 buf[1];
buf[0] = dat;
ret = i2c_master_reg8_send (i2c_connect_client1, reg, buf, 1);
return ret;
}
static u8 HDMI_ReadI2C_Byte(u8 reg)
{
int ret;
u8 buf[1];
ret = i2c_master_reg8_recv (i2c_connect_client1, reg, buf, 1);
return buf[0];
}
static int
lt9211_i2c_read_reg (struct i2c_client *client, u8 reg, u8 buf[],
unsigned len)
{
int ret;
ret = i2c_master_reg8_recv (client, reg, buf, len);
return ret;
}
static ssize_t lt9211_write (struct file *file, const char __user *buf, size_t count,
loff_t *off)
{
u8 addr;
int ret;
char *ker_buf = (char *) kzalloc (count, GFP_KERNEL);
lt9211_DEBUG ("write start!\n");
if (copy_from_user (ker_buf, buf + 1, count - 1))
{
return EFAULT;
}
addr = buf[0];
//rev_buf[0] = ker_buf[1];
for (ret = 0; ret < count; ret++)
{
lt9211_DEBUG ("write data is 0x%02x\n", buf[ret]);
lt9211_DEBUG (";");
}
lt9211_DEBUG ("\n");
//ret = lt9211_WriteI2C_Byte(i2c_connect_client1, addr, data);
ret = lt9211_i2c_set_reg (i2c_connect_client1, addr, ker_buf, count - 1);
if (!ret)
{
kfree (ker_buf);
return EFAULT;
}
else
{
kfree (ker_buf);
return ret;
}
}
static ssize_t lt9211_read (struct file *file, char __user *buf, size_t count,
loff_t *off)
{
u8 addr;
char *read_buf = (char *) kzalloc (count + 1, GFP_KERNEL);
int ret;
if (copy_from_user (read_buf, buf, count))
{
kfree (read_buf);
return EFAULT;
}
addr = read_buf[0];
// lt9211_ReadI2C_Byte(lt9211_client, addr, &data, 1);
ret = lt9211_i2c_read_reg (i2c_connect_client1, addr, read_buf, count);
// data = lt9211_Send_Get_Cmd(T2T_CMD_GET_STATUS, addr, 0x00);
if (copy_to_user (buf, read_buf, count))
{
kfree (read_buf);
return EFAULT;
}
kfree (read_buf);
return ret;
}
static int lt9211_open (struct inode *inode, struct file *file)
{
lt9211_DEBUG ("open device ok!\n");
return 0;
}
static struct file_operations lt9211_fops =
{
.owner = THIS_MODULE,
.read = lt9211_read,
.write = lt9211_write,
.open = lt9211_open,
};
//hfp, hs, hbp,hact,htotal,vfp, vs, vbp, vact,vtotal,
/*
struct video_timing video_640x480_60Hz ={ 8, 96, 40, 640, 800, 33, 2, 10, 480, 525, 25000};
struct video_timing video_720x480_60Hz ={16, 62, 60, 720, 858, 9, 6, 30, 480, 525, 27000};
struct video_timing video_1280x720_60Hz ={110,40, 220,1280, 1650, 5, 5, 20, 720, 750, 74250};
struct video_timing video_1280x720_30Hz ={110,40, 220,1280, 1650, 5, 5, 20, 720, 750, 74250};
struct video_timing video_1366x768_60Hz ={26, 110,110,1366, 1592, 13, 6, 13, 768, 800, 81000};
//struct video_timing video_1280x1024_60Hz ={100,100,208,1280, 1688, 5, 5, 32, 1024, 1066, 107960};
struct video_timing video_1920x1080_30Hz ={88, 44, 148,1920, 2200, 4, 5, 36, 1080, 1125, 74250};
struct video_timing video_1920x1080_60Hz ={88, 44, 148,1920, 2200, 4, 5, 36, 1080, 1125, 148500};
struct video_timing video_3840x1080_60Hz ={176,88, 296,3840, 4400, 4, 5, 36, 1080, 1125, 297000};
struct video_timing video_1920x1200_60Hz ={48, 32, 80,1920, 2080, 3, 6, 26, 1200, 1235, 154000};
struct video_timing video_3840x2160_30Hz ={176,88, 296,3840, 4400, 8, 10, 72, 2160, 2250, 297000};
struct video_timing video_3840x2160_60Hz ={176,88, 296,3840, 4400, 8, 10, 72, 2160, 2250, 594000};
*/
void LT9211_ChipID(void)
{
HDMI_WriteI2C_Byte(0xff, 0x81); //register bank
lt9211_DEBUG("LT9211 Chip ID:%x,%x,%x \n", HDMI_ReadI2C_Byte(0x00), HDMI_ReadI2C_Byte(0x01), HDMI_ReadI2C_Byte(0x02));
}
/** video chk soft rst **/
void lt9211_vid_chk_rst(void)
{
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x10, 0xbe);
mdelay(1);
HDMI_WriteI2C_Byte(0x10, 0xfe);
}
/** lvds rx logic rst **/
void lt9211_lvdsrx_logic_rst(void)
{
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x0c, 0xeb);
mdelay(1);
HDMI_WriteI2C_Byte(0x0c, 0xfb);
}
void LT9211_SystemInt(void)
{
/* system clock init */
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x01, 0x18);
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x06, 0x61);
HDMI_WriteI2C_Byte(0x07, 0xa8); //fm for sys_clk
HDMI_WriteI2C_Byte(0xff, 0x87); //³õʼ»¯ txpll ¼Ä´æÆ÷ÁбíĬÈÏÖµ¸ø´íÁË
HDMI_WriteI2C_Byte(0x14, 0x08); //default value
HDMI_WriteI2C_Byte(0x15, 0x00); //default value
HDMI_WriteI2C_Byte(0x18, 0x0f);
HDMI_WriteI2C_Byte(0x22, 0x08); //default value
HDMI_WriteI2C_Byte(0x23, 0x00); //default value
HDMI_WriteI2C_Byte(0x26, 0x0f);
}
void LT9211_LvdsRxPhy(void)
{
#ifdef INPUT_PORTA
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x02, 0x8B); //Port A LVDS mode enable
HDMI_WriteI2C_Byte(0x05, 0x21); //port A CLK lane swap
HDMI_WriteI2C_Byte(0x07, 0x1f); //port A clk enable
HDMI_WriteI2C_Byte(0x04, 0xa0); //select port A clk as byteclk
//HDMI_WriteI2C_Byte(0x09,0xFC); //port A P/N swap
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x33, 0xe4); //Port A Lane swap
#endif
#ifdef INPUT_PORTB
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x02, 0x88); //Port A/B LVDS mode enable
HDMI_WriteI2C_Byte(0x05, 0x21); //port A CLK lane swap and rterm turn-off
HDMI_WriteI2C_Byte(0x0d, 0x21); //port B CLK lane swap
HDMI_WriteI2C_Byte(0x07, 0x1f); //port A clk enable (Ö»¿ªPortbʱ,portaµÄlane0 clkÒª´ò¿ª)
HDMI_WriteI2C_Byte(0x0f, 0x1f); //port B clk enable
//HDMI_WriteI2C_Byte(0x10,0x00); //select port B clk as byteclk
HDMI_WriteI2C_Byte(0x04, 0xa1); //reserve
//HDMI_WriteI2C_Byte(0x11,0x01); //port B P/N swap
HDMI_WriteI2C_Byte(0x10, 0xfc);
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x34, 0xe4); //Port B Lane swap
HDMI_WriteI2C_Byte(0xff, 0xd8);
HDMI_WriteI2C_Byte(0x16, 0x80);
#endif
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x20, 0x7f);
HDMI_WriteI2C_Byte(0x20, 0xff); //mlrx calib reset
}
void LT9211_LvdsRxDigital(void)
{
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x88, 0x00); //LVDS input
HDMI_WriteI2C_Byte(0xff, 0xd8);
if(INPUT_PORT_NUM == 1) //1Port LVDS Input
{
HDMI_WriteI2C_Byte(0x10, 0x80);
lt9211_DEBUG("LVDS Port Num: 1\n");
}
else if(INPUT_PORT_NUM == 2) //2Port LVDS Input
{
HDMI_WriteI2C_Byte(0x10, 0x00);
lt9211_DEBUG("LVDS Port Num: 2\n");
}
else
{
lt9211_DEBUG("Port Num Set Error\n");
}
lt9211_vid_chk_rst(); //video chk soft rst
lt9211_lvdsrx_logic_rst(); //lvds rx logic rst
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x30, 0x45); //port AB input port sel
/*
#ifdef lvds_format_JEIDA
HDMI_WriteI2C_Byte(0xff,0x85);
HDMI_WriteI2C_Byte(0x59,0xd0);
HDMI_WriteI2C_Byte(0xff,0xd8);
HDMI_WriteI2C_Byte(0x11,0x40);
#endif
*/
}
int lt9211_lvds_clkstb_check(void)
{
u8 porta_clk_state = 0;
u8 portb_clk_state = 0;
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x00, 0x01);
mdelay(10);
porta_clk_state = (HDMI_ReadI2C_Byte(0x08) & (0x20));
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x00, 0x02);
mdelay(10);
portb_clk_state = (HDMI_ReadI2C_Byte(0x08) & (0x20));
if(INPUT_PORT_NUM == 1)
{
#ifdef INPUT_PORTA
if( porta_clk_state )
{
return 1;
}
else
{
return 0;
}
#endif
#ifdef INPUT_PORTB
if( portb_clk_state )
{
return 1;
}
else
{
return 0;
}
#endif
}
else if(INPUT_PORT_NUM == 2)
{
if(porta_clk_state && portb_clk_state)
{
return 1;
}
else
{
return 0;
}
}
}
void LT9211_ClockCheckDebug(void)
{
#ifdef _uart_debug_
u32 fm_value;
lvds_clk_in = 0;
#ifdef INPUT_PORTA
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x00, 0x01);
mdelay(10);
fm_value = 0;
fm_value = (HDMI_ReadI2C_Byte(0x08) & (0x0f));
fm_value = (fm_value << 8) ;
fm_value = fm_value + HDMI_ReadI2C_Byte(0x09);
fm_value = (fm_value << 8) ;
fm_value = fm_value + HDMI_ReadI2C_Byte(0x0a);
lt9211_DEBUG("Port A lvds clock: %d\n", fm_value);
lvds_clk_in = fm_value;
#endif
#ifdef INPUT_PORTB
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x00, 0x02);
mdelay(10);
fm_value = 0;
fm_value = (HDMI_ReadI2C_Byte(0x08) & (0x0f));
fm_value = (fm_value << 8) ;
fm_value = fm_value + HDMI_ReadI2C_Byte(0x09);
fm_value = (fm_value << 8) ;
fm_value = fm_value + HDMI_ReadI2C_Byte(0x0a);
lt9211_DEBUG("Port B lvds clock: %d\n", fm_value);
// printdec_u32(fm_value);
lvds_clk_in = fm_value;
#endif
#endif
}
void LT9211_LvdsRxPll(void)
{
u8 loopx = 0;
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x25, 0x05);
HDMI_WriteI2C_Byte(0x27, 0x02);
if(INPUT_PORT_NUM == 1) //1Port LVDS Input
{
HDMI_WriteI2C_Byte(0x24, 0x24); //RXPLL_LVDSCLK_MUXSEL,PIXCLK_MUXSEL 0x2c.
HDMI_WriteI2C_Byte(0x28, 0x44); //0x64
}
else if(INPUT_PORT_NUM == 2) //2Port LVDS Input
{
HDMI_WriteI2C_Byte(0x24, 0x2c); //RXPLL_LVDSCLK_MUXSEL,PIXCLK_MUXSEL 0x2c.
HDMI_WriteI2C_Byte(0x28, 0x64); //0x64
}
else
{
lt9211_DEBUG("LvdsRxPll: lvds port count error\n");
}
mdelay(10);
HDMI_WriteI2C_Byte(0xff, 0x87);
HDMI_WriteI2C_Byte(0x05, 0x00);
HDMI_WriteI2C_Byte(0x05, 0x80);
mdelay(100);
for(loopx = 0; loopx < 10; loopx++) //Check Rx PLL cal
{
HDMI_WriteI2C_Byte(0xff, 0x87);
if(HDMI_ReadI2C_Byte(0x12) & 0x80)
{
if(HDMI_ReadI2C_Byte(0x11) & 0x80)
{
lt9211_DEBUG("LT9211 rx cal done\n");
}
else
{
lt9211_DEBUG("LT9211 rx cal undone!!\n");
}
lt9211_DEBUG("LT9211 rx pll lock\n");
break;
}
else
{
lt9211_DEBUG("LT9211 rx pll unlocked\n");
}
}
}
void LT9211_TxDigital(void)
{
if( LT9211_OutPutModde == OUTPUT_RGB888 )
{
lt9211_DEBUG("LT9211 set to OUTPUT_RGB888\n");
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x88, 0x00);
HDMI_WriteI2C_Byte(0x60, 0x00);
HDMI_WriteI2C_Byte(0x6d, 0x00); //0x07
HDMI_WriteI2C_Byte(0x6E, 0x00);
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x36, 0xc0); //bit7:ttltx_pixclk_en;bit6:ttltx_BT_clk_en
}
else if( LT9211_OutPutModde == OUTPUT_BT656_8BIT )
{
lt9211_DEBUG("LT9211 set to OUTPUT_BT656_8BIT\n");
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x88, 0x00);
HDMI_WriteI2C_Byte(0x60, 0x34);
HDMI_WriteI2C_Byte(0x6d, 0x00); //0x08 YC SWAP
HDMI_WriteI2C_Byte(0x6e, 0x06); //High 8
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x0d, 0xfd);
HDMI_WriteI2C_Byte(0x0d, 0xff);
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x36, 0xc0); //bit7:ttltx_pixclk_en;bit6:ttltx_BT_clk_en
}
else if( LT9211_OutPutModde == OUTPUT_BT1120_16BIT )
{
lt9211_DEBUG("LT9211 set to OUTPUT_BT1120_16BIT\n");
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x88, 0x40);
HDMI_WriteI2C_Byte(0x60, 0x33);
HDMI_WriteI2C_Byte(0x6d, 0x08); //0x08 YC SWAP
HDMI_WriteI2C_Byte(0x6e, 0x06); //HIGH 16BIT
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x0d, 0xfd);
HDMI_WriteI2C_Byte(0x0d, 0xff);
}
else if( (LT9211_OutPutModde == OUTPUT_LVDS_2_PORT) || (LT9211_OutPutModde == OUTPUT_LVDS_1_PORT) )
{
HDMI_WriteI2C_Byte(0xff, 0x85); /* lvds tx controller */
HDMI_WriteI2C_Byte(0x59, 0x50);
HDMI_WriteI2C_Byte(0x5a, 0xaa);
HDMI_WriteI2C_Byte(0x5b, 0xaa);
if( LT9211_OutPutModde == OUTPUT_LVDS_2_PORT )
{
lt9211_DEBUG("LT9211 set to OUTPUT_LVDS_2PORT\n");
HDMI_WriteI2C_Byte(0x5c, 0x01); //lvdstx port sel 01:dual;00:single
}
else
{
lt9211_DEBUG("LT9211 set to OUTPUT_LVDS_1PORT\n");
HDMI_WriteI2C_Byte(0x5c, 0x00);
}
HDMI_WriteI2C_Byte(0x88, 0x00);
HDMI_WriteI2C_Byte(0xa1, 0x77);
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x40, 0x40); //tx_src_sel
/*port src sel*/
HDMI_WriteI2C_Byte(0x41, 0x34);
HDMI_WriteI2C_Byte(0x42, 0x10);
HDMI_WriteI2C_Byte(0x43, 0x23); //pt0_tx_src_sel
HDMI_WriteI2C_Byte(0x44, 0x41);
HDMI_WriteI2C_Byte(0x45, 0x02); //pt1_tx_src_scl
#ifdef lvds_format_JEIDA
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x59, 0xd0);
HDMI_WriteI2C_Byte(0xff, 0xd8);
HDMI_WriteI2C_Byte(0x11, 0x40);
#endif
}
}
void LT9211_TxPhy(void)
{
HDMI_WriteI2C_Byte(0xff, 0x82);
if( (LT9211_OutPutModde == OUTPUT_RGB888) || (LT9211_OutPutModde == OUTPUT_BT656_8BIT) || (LT9211_OutPutModde == OUTPUT_BT1120_16BIT) )
{
HDMI_WriteI2C_Byte(0x62, 0x01); //ttl output enable
HDMI_WriteI2C_Byte(0x6b, 0xff);
}
else if( (LT9211_OutPutModde == OUTPUT_LVDS_2_PORT) || (LT9211_OutPutModde == OUTPUT_LVDS_1_PORT) )
{
/* dual-port lvds tx phy */
HDMI_WriteI2C_Byte(0x62, 0x00); //ttl output disable
if(LT9211_OutPutModde == OUTPUT_LVDS_2_PORT)
{
HDMI_WriteI2C_Byte(0x3b, 0xb8);
}
else
{
HDMI_WriteI2C_Byte(0x3b, 0x38);
}
// HDMI_WriteI2C_Byte(0x3b,0xb8); //dual port lvds enable
HDMI_WriteI2C_Byte(0x3e, 0x92);
HDMI_WriteI2C_Byte(0x3f, 0x48);
HDMI_WriteI2C_Byte(0x40, 0x31);
HDMI_WriteI2C_Byte(0x43, 0x80);
HDMI_WriteI2C_Byte(0x44, 0x00);
HDMI_WriteI2C_Byte(0x45, 0x00);
HDMI_WriteI2C_Byte(0x49, 0x00);
HDMI_WriteI2C_Byte(0x4a, 0x01);
HDMI_WriteI2C_Byte(0x4e, 0x00);
HDMI_WriteI2C_Byte(0x4f, 0x00);
HDMI_WriteI2C_Byte(0x50, 0x00);
HDMI_WriteI2C_Byte(0x53, 0x00);
HDMI_WriteI2C_Byte(0x54, 0x01);
HDMI_WriteI2C_Byte(0xff, 0x81);
HDMI_WriteI2C_Byte(0x20, 0x7b);
HDMI_WriteI2C_Byte(0x20, 0xff); //mlrx mltx calib reset
}
}
void LT9211_Txpll(void)
{
u8 loopx;
u16 m_value = 2;
if( LT9211_OutPutModde == OUTPUT_BT656_8BIT )
{
//HDMI_WriteI2C_Byte(0xff,0x82);
//HDMI_WriteI2C_Byte(0x2d,0x48);
//HDMI_WriteI2C_Byte(0x30,0x53);
//HDMI_WriteI2C_Byte(0x33,0x13);
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x2d, 0x98);
if(lvds_clk_in < 10000)
{
return;
}
while(lvds_clk_in * m_value < 352000)
{
m_value = m_value << 1;
// printdec_u32(m_value);
}
HDMI_WriteI2C_Byte(0x34, (m_value - 2) | 0x80);
if( (m_value / 2) == 1 )
{
HDMI_WriteI2C_Byte(0x30, 0x40);
HDMI_WriteI2C_Byte(0x33, 0x10);
}
else if( (m_value / 2) == 2 )
{
HDMI_WriteI2C_Byte(0x30, 0x41);
HDMI_WriteI2C_Byte(0x33, 0x11);
}
else if( (m_value / 2) == 4 )
{
HDMI_WriteI2C_Byte(0x30, 0x42);
HDMI_WriteI2C_Byte(0x33, 0x12);
}
else if( (m_value / 2) == 8 )
{
HDMI_WriteI2C_Byte(0x30, 0x43);
HDMI_WriteI2C_Byte(0x33, 0x13);
}
}
else if( (LT9211_OutPutModde == OUTPUT_LVDS_2_PORT) || (LT9211_OutPutModde == OUTPUT_LVDS_1_PORT) || (LT9211_OutPutModde == OUTPUT_RGB888) || (LT9211_OutPutModde == OUTPUT_BT1120_16BIT) )
{
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x36, 0x01); //b7:txpll_pd
if( LT9211_OutPutModde == OUTPUT_LVDS_1_PORT )
{
HDMI_WriteI2C_Byte(0x37, 0x29);
}
else
{
HDMI_WriteI2C_Byte(0x37, 0x2a);
}
HDMI_WriteI2C_Byte(0x38, 0x06);
HDMI_WriteI2C_Byte(0x39, 0x30);
HDMI_WriteI2C_Byte(0x3a, 0x8e);
HDMI_WriteI2C_Byte(0xff, 0x87);
HDMI_WriteI2C_Byte(0x37, 0x14);
HDMI_WriteI2C_Byte(0x13, 0x00);
HDMI_WriteI2C_Byte(0x13, 0x80);
mdelay(10);
for(loopx = 0; loopx < 10; loopx++) //Check Tx PLL cal
{
HDMI_WriteI2C_Byte(0xff, 0x87);
if(HDMI_ReadI2C_Byte(0x1f) & 0x80)
{
if(HDMI_ReadI2C_Byte(0x20) & 0x80)
{
lt9211_DEBUG("LT9211 tx pll lock\n");
}
else
{
lt9211_DEBUG("LT9211 tx pll unlocked\n");
}
lt9211_DEBUG("LT9211 tx pll cal done\n");
break;
}
else
{
lt9211_DEBUG("LT9211 tx pll unlocked\n");
}
}
}
}
void LT9211_RXCSC(void)
{
HDMI_WriteI2C_Byte(0xff, 0xf9);
if( LT9211_OutPutModde == OUTPUT_RGB888 )
{
if( Video_Input_Mode == Input_RGB888 )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x00);
}
else if ( Video_Input_Mode == Input_YCbCr444 )
{
HDMI_WriteI2C_Byte(0x86, 0x0f);
HDMI_WriteI2C_Byte(0x87, 0x00);
}
else if ( Video_Input_Mode == Input_YCbCr422_16BIT )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x03);
}
}
else if( (LT9211_OutPutModde == OUTPUT_BT656_8BIT) || (LT9211_OutPutModde == OUTPUT_BT1120_16BIT) || (LT9211_OutPutModde == OUTPUT_YCbCr422_16BIT) )
{
if( Video_Input_Mode == Input_RGB888 )
{
HDMI_WriteI2C_Byte(0x86, 0x0f);
HDMI_WriteI2C_Byte(0x87, 0x30);
}
else if ( Video_Input_Mode == Input_YCbCr444 )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x30);
}
else if ( Video_Input_Mode == Input_YCbCr422_16BIT )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x00);
}
}
else if( LT9211_OutPutModde == OUTPUT_YCbCr444 )
{
if( Video_Input_Mode == Input_RGB888 )
{
HDMI_WriteI2C_Byte(0x86, 0x0f);
HDMI_WriteI2C_Byte(0x87, 0x00);
}
else if ( Video_Input_Mode == Input_YCbCr444 )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x00);
}
else if ( Video_Input_Mode == Input_YCbCr422_16BIT )
{
HDMI_WriteI2C_Byte(0x86, 0x00);
HDMI_WriteI2C_Byte(0x87, 0x03);
}
}
}
void LT9211_BT_Set(void)
{
u16 tmp_data;
if( (LT9211_OutPutModde == OUTPUT_BT1120_16BIT) || (LT9211_OutPutModde == OUTPUT_BT656_8BIT) )
{
tmp_data = hs + hbp;
HDMI_WriteI2C_Byte(0xff, 0x85);
HDMI_WriteI2C_Byte(0x61, (u8)(tmp_data >> 8));
HDMI_WriteI2C_Byte(0x62, (u8)tmp_data);
HDMI_WriteI2C_Byte(0x63, (u8)(hact >> 8));
HDMI_WriteI2C_Byte(0x64, (u8)hact);
HDMI_WriteI2C_Byte(0x65, (u8)(htotal >> 8));
HDMI_WriteI2C_Byte(0x66, (u8)htotal);
tmp_data = vs + vbp;
HDMI_WriteI2C_Byte(0x67, (u8)tmp_data);
HDMI_WriteI2C_Byte(0x68, 0x00);
HDMI_WriteI2C_Byte(0x69, (u8)(vact >> 8));
HDMI_WriteI2C_Byte(0x6a, (u8)vact);
HDMI_WriteI2C_Byte(0x6b, (u8)(vtotal >> 8));
HDMI_WriteI2C_Byte(0x6c, (u8)vtotal);
}
}
void LT9211_VideoCheck(void)
{
#ifdef _uart_debug_
u8 sync_polarity;
HDMI_WriteI2C_Byte(0xff, 0x86);
HDMI_WriteI2C_Byte(0x20, 0x00);
mdelay(10);
sync_polarity = HDMI_ReadI2C_Byte(0x70);
vs = HDMI_ReadI2C_Byte(0x71);
hs = HDMI_ReadI2C_Byte(0x72);
hs = (hs << 8) + HDMI_ReadI2C_Byte(0x73);
vbp = HDMI_ReadI2C_Byte(0x74);
vfp = HDMI_ReadI2C_Byte(0x75);
hbp = HDMI_ReadI2C_Byte(0x76);
hbp = (hbp << 8) + HDMI_ReadI2C_Byte(0x77);
hfp = HDMI_ReadI2C_Byte(0x78);
hfp = (hfp << 8) + HDMI_ReadI2C_Byte(0x79);
vtotal = HDMI_ReadI2C_Byte(0x7A);
vtotal = (vtotal << 8) + HDMI_ReadI2C_Byte(0x7B);
htotal = HDMI_ReadI2C_Byte(0x7C);
htotal = (htotal << 8) + HDMI_ReadI2C_Byte(0x7D);
vact = HDMI_ReadI2C_Byte(0x7E);
vact = (vact << 8) + HDMI_ReadI2C_Byte(0x7F);
hact = HDMI_ReadI2C_Byte(0x80);
hact = (hact << 8) + HDMI_ReadI2C_Byte(0x81);
lt9211_DEBUG("sync_polarity = %x\n", sync_polarity);
lt9211_DEBUG("hfp, hs, hbp, hact, htotal = %d,%d,%d,%d,%d\n", hfp, hs, hbp, hact, htotal);
// printk(hfp);
// printdec_u32(hs);
// printdec_u32(hbp);
// printdec_u32(hact);
// printdec_u32(htotal);
lt9211_DEBUG("vfp, vs, vbp, vact, vtotal = %d,%d,%d,%d,%d\n", vfp, vs, vbp, vact, vtotal);
// printdec_u32(vfp);
// printdec_u32(vs);
// printdec_u32(vbp);
// printdec_u32(vact);
// printdec_u32(vtotal);
#endif
}
static void LT9211_Config(void)
{
LT9211_ChipID();
LT9211_SystemInt();
LT9211_LvdsRxPhy();
LT9211_LvdsRxDigital();
LT9211_LvdsRxPll();
}
static void LT9211_Config_Tx(void)
{
while( lt9211_lvds_clkstb_check() <= 0) //wait for stable
{
}
LT9211_ClockCheckDebug();
LT9211_LvdsRxPll();
lt9211_vid_chk_rst(); //video chk soft rst
lt9211_lvdsrx_logic_rst();
mdelay(100);
LT9211_VideoCheck();
//Tx config
LT9211_TxPhy();
LT9211_TxDigital();
LT9211_Txpll();
LT9211_RXCSC();
LT9211_BT_Set();
}
static int lt9211_init_device(void)
{
LT9211_Config();
LT9211_Config_Tx();
pr_info ("lt9211 config ok\n");
return 0;
}
/*thread service*/
static int
lt9211_attached_thread (void *data)
{
lt9211_init_device();
return 0;
}
static int lt9211_ic_probe (struct i2c_client *client, const struct i2c_device_id *id)
{
struct lt9211_DATA *pdata = NULL;
struct task_struct *thread = NULL;
// enum of_gpio_flags flag;
// struct device_node *motor_node = client->dev.of_node;
if (!i2c_check_functionality (client->adapter, I2C_FUNC_I2C))
{
lt9211_DEBUG ("[%s]:%d check_functionlity failed !\n", __func__,
__LINE__);
return -ENOMEM;
}
pdata = kzalloc (sizeof (struct lt9211_DATA), GFP_KERNEL);
if (!pdata)
{
lt9211_DEBUG ("[%s]:%d memory allocation faild !\n", __func__,
__LINE__);
goto ERR0;
}
i2c_set_clientdata (client, pdata);
i2c_connect_client1 = pdata->lt9211 = client;
dev_info(&client->dev,"%s at Adapter %d Addr = 0x%x\n",
lt9211_I2C_NAME, i2c_adapter_id (pdata->lt9211->adapter),
pdata->lt9211->addr);
lt9211_DEBUG ("Probe end!\n");
thread = kthread_run (lt9211_attached_thread, pdata, "lt9211-attached");
if (IS_ERR (thread))
{
dev_warn (&client->dev, "Unable to start lt9211 attached thread\n");
return PTR_ERR (thread);
}
pdata->attached_thread = thread;
return 0;
ERR0:
kfree (pdata);
return -ENOMEM;
}
static int lt9211_ic_remove (struct i2c_client *client)
{
struct lt9211_DATA *del_lt9211;
i2c_set_clientdata (client, NULL);
del_lt9211 = i2c_get_clientdata (client);
kfree (del_lt9211);
return 0;
}
static const struct i2c_device_id lt9211_ic_id[] =
{
{lt9211_I2C_NAME, 0},
{}
};
#ifdef CONFIG_PM
static int lt9211_suspend(struct device *dev, pm_message_t state)
{
// struct ruichi_motor_dev *ldev = platform_get_drvdata(pdev);
/* set led off */
pr_info("lt9211 suspend ok\n");
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x62, 0x00); //ttl output enable
return 0;
}
static int lt9211_resume(struct device *pdev)
{
// struct ruichi_motor_dev *ldev = platform_get_drvdata(pdev);
/* set led on */
pr_info("lt9211 resume ok\n");
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x62, 0x01); //ttl output enable
return 0;
}
#endif
MODULE_DEVICE_TABLE (i2c, lt9211_ic_id);
static struct of_device_id lt9211_dt_ids[] =
{
{.compatible = "lt9211"},
{},
};
static struct i2c_driver lt9211_ic_driver =
{
.driver = {
.name = lt9211_I2C_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr (lt9211_dt_ids),
#ifdef CONFIG_PM
.suspend = lt9211_suspend,
.resume = lt9211_resume,
#endif
},
.probe = lt9211_ic_probe,
.remove = lt9211_ic_remove,
.id_table = lt9211_ic_id,
};
static ssize_t motor_debug_show(struct class *class,
struct class_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", "HDMI_WriteI2C_Byte(0xff, 0x82);");
}
static ssize_t motor_debug_store(struct class *class,
struct class_attribute *attr, const char *buf, size_t count)
{
unsigned int val;
int ret;
ret = sscanf(buf, "%d", &val);
if (ret == 1) { //success
if(val ==1){
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x62, 0x01); //ttl output enable
} else {
HDMI_WriteI2C_Byte(0xff, 0x82);
HDMI_WriteI2C_Byte(0x62, 0x00); //ttl output enable
}
} else {
pr_info("invalid data\n");
return -EINVAL;
}
return count;
}
static struct class_attribute lt9211_class_attrs[] =
{
__ATTR(debug, 0644,
motor_debug_show, motor_debug_store),
};
static int __init lt9211_init (void)
{
int ret,i;
ret = i2c_add_driver (<9211_ic_driver);
if (ret)
{
pr_err("i2c_add_driver fail!\n");
i2c_del_driver (<9211_ic_driver);
return ENOMEM;
}
major = register_chrdev (0, "lt9211", <9211_fops);
class = class_create (THIS_MODULE, "lt9211");
if (IS_ERR (class))
{
pr_err("class_create error..\n");
return -1;
}
for (i = 0; i < ARRAY_SIZE(lt9211_class_attrs); i++)
{
if (class_create_file(class,
<9211_class_attrs[i]))
{
pr_info("create debug attribute %s failed\n",
lt9211_class_attrs[i].attr.name);
}
}
return 0;
device_create (class, NULL, MKDEV (major, 0), NULL, "lt9211");
return 0;
}
static void __exit lt9211_exit (void)
{
i2c_del_driver (<9211_ic_driver);
unregister_chrdev (major, "lt9211");
device_destroy (class, MKDEV (major, 0));
class_destroy (class);
}
//subsys_initcall(lt9211_init);
module_init(lt9211_init);
module_exit (lt9211_exit);
MODULE_DESCRIPTION (" lt9211 IR Driver");
MODULE_AUTHOR ("hanbin <zhanghb@ruichi-group.com>");
MODULE_LICENSE ("GPL");
网友评论