美文网首页
amlogic T972 的lt9211驱动

amlogic T972 的lt9211驱动

作者: Wood木木 | 来源:发表于2023-04-10 10:31 被阅读0次

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 (&lt9211_ic_driver);
    if (ret)
    {
        pr_err("i2c_add_driver fail!\n");
        i2c_del_driver (&lt9211_ic_driver);
        return ENOMEM;
    }
    major = register_chrdev (0, "lt9211", &lt9211_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,
                              &lt9211_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 (&lt9211_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");

相关文章

网友评论

      本文标题:amlogic T972 的lt9211驱动

      本文链接:https://www.haomeiwen.com/subject/ffgiddtx.html