美文网首页
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