OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/misc/dp_anx6345.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

1310 lines
34 KiB
C

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/fb.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include<linux/earlysuspend.h>
#endif
#include "anx6345.h"
#include "dpcd_edid.h"
#include <linux/debugfs.h>
static struct edp_anx6345 *edp;
//#define BIST_MODE 0
static int i2c_master_reg8_send(const struct i2c_client *client,
const char reg, const char *buf, int count, int scl_rate)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
char *tx_buf = (char *)kmalloc(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;
// msg.scl_rate = scl_rate;
ret = i2c_transfer(adap, &msg, 1);
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, int scl_rate)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msgs[2];
int ret;
char reg_buf = reg;
msgs[0].addr = client->addr;
msgs[0].flags = client->flags;
msgs[0].len = 1;
msgs[0].buf = &reg_buf;
//msgs[0].scl_rate = scl_rate;
msgs[1].addr = client->addr;
msgs[1].flags = client->flags | I2C_M_RD;
msgs[1].len = count;
msgs[1].buf = (char *)buf;
//msgs[1].scl_rate = scl_rate;
ret = i2c_transfer(adap, msgs, 2);
return (ret == 2)? count : ret;
}
static int anx6345_i2c_read_p0_reg(struct i2c_client *client, char reg, char *val)
{
int ret;
client->addr = DP_TX_PORT0_ADDR >> 1;
ret = i2c_master_reg8_recv(client, reg, val, 1, ANX6345_SCL_RATE) > 0? 0: -EINVAL;
if(ret < 0)
{
printk(KERN_ERR "%s>>err\n",__func__);
}
return ret;
}
static int anx6345_i2c_write_p0_reg(struct i2c_client *client, char reg, char *val)
{
int ret;
client->addr = DP_TX_PORT0_ADDR >> 1;
ret = i2c_master_reg8_send(client, reg, val, 1, ANX6345_SCL_RATE) > 0? 0: -EINVAL;
if(ret < 0)
{
printk(KERN_ERR "%s>>err\n",__func__);
}
return ret;
}
static int anx6345_i2c_read_p1_reg(struct i2c_client *client, char reg, char *val)
{
int ret;
client->addr = HDMI_TX_PORT0_ADDR >> 1;
ret = i2c_master_reg8_recv(client, reg, val, 1, ANX6345_SCL_RATE) > 0? 0: -EINVAL;
if(ret < 0)
{
printk(KERN_ERR "%s>>err\n",__func__);
}
return ret;
}
static int anx6345_i2c_write_p1_reg(struct i2c_client *client, char reg, char *val)
{
int ret;
client->addr = HDMI_TX_PORT0_ADDR >> 1;
ret = i2c_master_reg8_send(client, reg, val, 1, ANX6345_SCL_RATE) > 0? 0: -EINVAL;
if(ret < 0)
{
printk(KERN_ERR "%s>>err\n",__func__);
}
return ret;
}
#if 0
static int edp_reg_show(struct seq_file *s, void *v)
{
int i = 0;
char val;
struct edp_anx6345 *anx6345 = s->private;
if(!anx6345)
{
printk(KERN_ERR "no edp device!\n");
return 0;
}
seq_printf(s,"0x70:\n");
for(i=0;i< MAX_REG;i++)
{
anx6345_i2c_read_p0_reg(anx6345->client, i , &val);
seq_printf(s,"0x%02x>>0x%02x\n",i,val);
}
seq_printf(s,"\n0x72:\n");
for(i=0;i< MAX_REG;i++)
{
anx6345_i2c_read_p1_reg(anx6345->client, i , &val);
seq_printf(s,"0x%02x>>0x%02x\n",i,val);
}
return 0;
}
static int edp_reg_open(struct inode *inode, struct file *file)
{
struct edp_anx6345 *anx6345 = inode->i_private;
return single_open(file, edp_reg_show, anx6345);
}
static const struct file_operations edp_reg_fops = {
.owner = THIS_MODULE,
.open = edp_reg_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#endif
//get chip ID. Make sure I2C is OK
static int get_dp_chip_id(struct i2c_client *client)
{
char c1,c2;
int id;
anx6345_i2c_read_p1_reg(client,DEV_IDL_REG,&c1);
anx6345_i2c_read_p1_reg(client,DEV_IDH_REG,&c2);
id = c2;
return (id<<8)|c1;
}
static int anx980x_bist_mode(struct i2c_client *client)
{
char val,i;
u8 cnt=0;
//Power on total and select DP mode
val = 00;
anx6345_i2c_write_p1_reg(client, DP_POWERD_CTRL_REG, &val);
//HW reset
val = DP_TX_RST_HW_RST;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL_REG, &val);
msleep(10);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL_REG, &val);
anx6345_i2c_read_p1_reg(client, DP_POWERD_CTRL_REG, &val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_POWERD_CTRL_REG, &val);
//get chip ID. Make sure I2C is OK
anx6345_i2c_read_p1_reg(client, DP_TX_DEV_IDH_REG , &val);
if (val==0x98)
printk("Chip found\n");
//for clocl detect
for(i=0;i<100;i++)
{
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL1_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_SYS_CTRL1_REG, &val);
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL1_REG, &val);
if((val&DP_TX_SYS_CTRL1_DET_STA)!=0)
{
printk("clock is detected.\n");
break;
}
msleep(10);
}
//check whther clock is stable
for(i=0;i<50;i++)
{
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
if((val&DP_TX_SYS_CTRL2_CHA_STA)==0)
{
printk("clock is stable.\n");
break;
}
msleep(10);
}
//VESA range, 8bits BPC, RGB
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL2_REG, &val);
//RK_EDP chip analog setting
val = 0x07;
anx6345_i2c_write_p0_reg(client, DP_TX_PLL_CTRL_REG, &val);
val = 0x19;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL3, &val);
val = 0xd9;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_CTRL3, &val);
//Select AC mode
val = 0x40;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
//RK_EDP chip analog setting
val = 0xf0;
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG1, &val);
val = 0x99;
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG3, &val);
val = 0x7b;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL1, &val);
val = 0x30;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_DEBUG_REG,&val);
val = 0x06;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL, &val);
//force HPD
val = 0x30;
anx6345_i2c_write_p0_reg(client, DP_TX_SYS_CTRL3_REG, &val);
//power on 4 lanes
val = 0x00;
anx6345_i2c_write_p0_reg(client, 0xc8, &val);
//lanes setting
anx6345_i2c_write_p0_reg(client, 0xa3, &val);
anx6345_i2c_write_p0_reg(client, 0xa4, &val);
anx6345_i2c_write_p0_reg(client, 0xa5,&val);
anx6345_i2c_write_p0_reg(client, 0xa6, &val);
//reset AUX CH
val = 0x44;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
val = 0x40;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
//Select 1.62G
val = 0x0a;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_BW_SET_REG, &val);
//Select 4 lanes
val = 0x01;
anx6345_i2c_write_p0_reg(client, DP_TX_LANE_COUNT_SET_REG, &val);
//strart link traing
//DP_TX_LINK_TRAINING_CTRL_EN is self clear. If link training is OK, it will self cleared.
#if 1
val = DP_TX_LINK_TRAINING_CTRL_EN;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG, &val);
msleep(5);
anx6345_i2c_read_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG, &val);
while((val&0x01)&&(cnt++ < 10))
{
printk("Waiting...\n");
msleep(5);
anx6345_i2c_read_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG, &val);
}
if(cnt >= 10)
{
printk(KERN_INFO "HW LT fail\n");
}
else
{
printk(KERN_INFO "HW LT success ...cnt:%d\n",cnt);
}
#else
DP_TX_HW_LT(client,0x0a,0x04); //2.7Gpbs 4lane
#endif
//DP_TX_Write_Reg(0x7a, 0x7c, 0x02);
//Set bist format 2048x1536
val = 0x2c;
anx6345_i2c_write_p1_reg(client, DP_TX_TOTAL_LINEL_REG, &val);
val = 0x06;
anx6345_i2c_write_p1_reg(client, DP_TX_TOTAL_LINEH_REG, &val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_ACT_LINEL_REG, &val);
val = 0x06;
anx6345_i2c_write_p1_reg(client, DP_TX_ACT_LINEH_REG,&val);
val = 0x02;
anx6345_i2c_write_p1_reg(client, DP_TX_VF_PORCH_REG, &val);
val = 0x04;
anx6345_i2c_write_p1_reg(client, DP_TX_VSYNC_CFG_REG,&val);
val = 0x26;
anx6345_i2c_write_p1_reg(client, DP_TX_VB_PORCH_REG, &val);
val = 0x50;
anx6345_i2c_write_p1_reg(client, DP_TX_TOTAL_PIXELL_REG, &val);
val = 0x04;
anx6345_i2c_write_p1_reg(client, DP_TX_TOTAL_PIXELH_REG, &val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_ACT_PIXELL_REG, &val);
val = 0x04;
anx6345_i2c_write_p1_reg(client, DP_TX_ACT_PIXELH_REG, &val);
val = 0x18;
anx6345_i2c_write_p1_reg(client, DP_TX_HF_PORCHL_REG, &val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_HF_PORCHH_REG, &val);
val = 0x10;
anx6345_i2c_write_p1_reg(client, DP_TX_HSYNC_CFGL_REG,&val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_HSYNC_CFGH_REG,&val);
val = 0x28;
anx6345_i2c_write_p1_reg(client, DP_TX_HB_PORCHL_REG, &val);
val = 0x00;
anx6345_i2c_write_p1_reg(client, DP_TX_HB_PORCHH_REG, &val);
val = 0x03;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL10_REG, &val);
//enable BIST
val = DP_TX_VID_CTRL4_BIST;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL4_REG, &val);
//enable video input
val = 0x8d;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);
//force HPD and stream valid
val = 0x33;
anx6345_i2c_write_p0_reg(client, 0x82, &val);
return 0;
}
static int anx980x_aux_rst(struct i2c_client *client)
{
char val;
anx6345_i2c_read_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
val |= DP_TX_AUX_RST;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
val &= ~DP_TX_AUX_RST;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
return 0;
}
static int anx980x_wait_aux_finished(struct i2c_client *client)
{
char val,cnt;
cnt = 0;
anx6345_i2c_read_p0_reg(client,DP_TX_AUX_CTRL_REG2, &val);
while(val&0x01)
{
//delay_ms(20);
cnt ++;
if(cnt == 10)
{
printk("aux break");
anx980x_aux_rst(client);
//cnt = 0;
break;
}
anx6345_i2c_read_p0_reg(client, DP_TX_AUX_CTRL_REG2, &val);
}
return 0;
}
static int anx980x_aux_dpcdread_bytes(struct i2c_client *client,unsigned long addr, char cCount,char* pBuf)
{
char val,i;
val = 0x80;
anx6345_i2c_write_p0_reg(client, DP_TX_BUF_DATA_COUNT_REG, &val);
//set read cmd and count
val = (((char)(cCount-1) <<4)&(0xf0))|0x09;
anx6345_i2c_write_p0_reg(client, DP_TX_AUX_CTRL_REG, &val);
//set aux address15:0
val = (char)addr&0xff;
anx6345_i2c_write_p0_reg(client, DP_TX_AUX_ADDR_7_0_REG, &val);
val = (char)((addr>>8)&0xff);
anx6345_i2c_write_p0_reg(client, DP_TX_AUX_ADDR_15_8_REG, &val);
//set address19:16 and enable aux
anx6345_i2c_read_p0_reg(client, DP_TX_AUX_ADDR_19_16_REG, &val);
val &=(0xf0)|(char)((addr>>16)&0xff);
anx6345_i2c_write_p0_reg(client, DP_TX_AUX_ADDR_19_16_REG, &val);
//Enable Aux
anx6345_i2c_read_p0_reg(client, DP_TX_AUX_CTRL_REG2, &val);
val |= 0x01;
anx6345_i2c_write_p0_reg(client, DP_TX_AUX_CTRL_REG2, &val);
//delay_ms(2);
anx980x_wait_aux_finished(client);
for(i =0;i<cCount;i++)
{
anx6345_i2c_read_p0_reg(client, DP_TX_BUF_DATA_0_REG+i, &val);
//debug_printf("c = %.2x\n",(WORD)c);
*(pBuf+i) = val;
if(i >= MAX_BUF_CNT)
return 1;
//break;
}
return 0;
}
static int anx_video_map_config(struct i2c_client *client)
{
char val = 0;
char i = 0;
anx6345_i2c_write_p1_reg(client, 0x40, &val);
anx6345_i2c_write_p1_reg(client, 0x41, &val);
anx6345_i2c_write_p1_reg(client, 0x48, &val);
anx6345_i2c_write_p1_reg(client, 0x49, &val);
anx6345_i2c_write_p1_reg(client, 0x50, &val);
anx6345_i2c_write_p1_reg(client, 0x51, &val);
for(i=0; i<1; i++)
{
val = i;
anx6345_i2c_write_p1_reg(client, 0x42+i, &val);
}
for(i=0; i<1; i++)
{
val = 1+i;
anx6345_i2c_write_p1_reg(client, 0x4a+i, &val);
}
for(i=0; i<1; i++)
{
val = 0x0c+i;
anx6345_i2c_write_p1_reg(client, 0x52+i, &val);
}
return 0;
}
static int anx980x_eanble_video_input(struct i2c_client *client)
{
char val;
anx6345_i2c_read_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);
val |= DP_TX_VID_CTRL1_VID_EN;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);
anx_video_map_config(client);
return 0;
}
static int anx980x_init(struct i2c_client *client)
{
char val = 0x00;
char safe_mode = 0;
char ByteBuf[2];
char dp_tx_bw,dp_tx_lane_count;
char cnt = 10;
#if defined(BIST_MODE)
return anx980x_bist_mode(client);
#endif
//power on all block and select DisplayPort mode
val |= DP_POWERD_AUDIO_REG;
anx6345_i2c_write_p1_reg(client, DP_POWERD_CTRL_REG, &val );
anx6345_i2c_read_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);
val &= ~DP_TX_VID_CTRL1_VID_EN;
anx6345_i2c_read_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);
//software reset
anx6345_i2c_read_p1_reg(client, DP_TX_RST_CTRL_REG, &val);
val |= DP_TX_RST_SW_RST;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL_REG,&val);
val &= ~DP_TX_RST_SW_RST;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL_REG, &val);
val = 0x07;
anx6345_i2c_write_p0_reg(client, DP_TX_PLL_CTRL_REG, &val);
val = 0x50;
anx6345_i2c_write_p0_reg(client, DP_TX_EXTRA_ADDR_REG, &val);
//24bit SDR,negedge latch, and wait video stable
val = 0x01;
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL1_REG, &val);//72:08 for 9804 SDR, neg edge 05/04/09 extra pxl
val = 0x19;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL3, &val);
val = 0xd9;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_CTRL3, &val);
//serdes ac mode.
anx6345_i2c_read_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
val |= DP_TX_AC_MODE;
anx6345_i2c_write_p1_reg(client, DP_TX_RST_CTRL2_REG, &val);
//set termination
val = 0xf0;
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG1, &val);
//set duty cycle
val = 0x99;
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG3, &val);
anx6345_i2c_read_p1_reg(client, DP_TX_PLL_FILTER_CTRL1, &val);
val |= 0x2a;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL1, &val);
//anx6345_i2c_write_p0_reg(client, DP_TX_HDCP_CTRL, 0x01);
val = 0x30;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_DEBUG_REG,&val);
//for DP link CTS
anx6345_i2c_read_p0_reg(client, DP_TX_GNS_CTRL_REG, &val);
val |= 0x40;
anx6345_i2c_write_p0_reg(client, DP_TX_GNS_CTRL_REG, &val);
//power down PLL filter
val = 0x06;
anx6345_i2c_write_p1_reg(client, DP_TX_PLL_FILTER_CTRL,&val);
anx6345_i2c_write_p0_reg(client, DP_TX_TRAINING_LANE0_SET_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_TRAINING_LANE1_SET_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_TRAINING_LANE2_SET_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_TRAINING_LANE3_SET_REG, &val);
val = 0x0a;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_BW_SET_REG, &val);
val = 0x01;
anx6345_i2c_write_p0_reg(client, DP_TX_LANE_COUNT_SET_REG, &val);
val = DP_TX_LINK_TRAINING_CTRL_EN;
anx6345_i2c_write_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG,&val);
msleep(2);
anx6345_i2c_read_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG, &val);
while((val & DP_TX_LINK_TRAINING_CTRL_EN)&&(cnt--))
{
anx6345_i2c_read_p0_reg(client, DP_TX_LINK_TRAINING_CTRL_REG, &val);
cnt--;
}
if(cnt < 0)
{
printk(KERN_INFO "HW LT fail\n");
}
else
printk(KERN_INFO "HW LT Success!>>:times:%d\n",(11-cnt));
//DP_TX_Config_Video(client);
anx6345_i2c_write_p0_reg(client, DP_TX_SYS_CTRL1_REG, &val);
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL1_REG, &val);
if(!(val & DP_TX_SYS_CTRL1_DET_STA))
{
printk("No pclk\n");
//return; //mask by yxj
}
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
anx6345_i2c_write_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
anx6345_i2c_read_p0_reg(client, DP_TX_SYS_CTRL2_REG, &val);
if(val & DP_TX_SYS_CTRL2_CHA_STA)
{
printk("pclk not stable!\n");
//return; mask by yxj
}
anx980x_aux_dpcdread_bytes(client,(unsigned long)0x00001,2,ByteBuf);
dp_tx_bw = ByteBuf[0];
dp_tx_lane_count = ByteBuf[1] & 0x0f;
printk("%s..lc:%d--bw:%d\n",__func__,dp_tx_lane_count,dp_tx_bw);
if(!safe_mode)
{
//set Input BPC mode & color space
anx6345_i2c_read_p1_reg(client, DP_TX_VID_CTRL2_REG, &val);
val &= 0x8c;
val = val |((char)(0) << 4); //8bits ,rgb
anx6345_i2c_write_p1_reg(client, DP_TX_VID_CTRL2_REG, &val);
}
//enable video input
anx980x_eanble_video_input(client);
return 0;
}
static int anx6345_bist_mode(struct i2c_client *client)
{
return 0;
}
int anx6345_start_aux_transaction(struct i2c_client *client)
{
char val;
int retval = 0;
int timeout_loop = 0;
int aux_timeout = 0;
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
val |= AUX_EN;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_2, &val);
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
while (val & AUX_EN) {
aux_timeout++;
if ((DP_TIMEOUT_LOOP_CNT * 10) < aux_timeout) {
dev_err(&client->dev, "AUX CH enable timeout!\n");
return -ETIMEDOUT;
}
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
udelay(100);
}
/* Is AUX CH command redply received? */
anx6345_i2c_read_p1_reg(client, DP_INT_STA, &val);
while (!(val & RPLY_RECEIV)) {
timeout_loop++;
if (DP_TIMEOUT_LOOP_CNT < timeout_loop) {
dev_err(&client->dev, "AUX CH command redply failed!\n");
return -ETIMEDOUT;
}
anx6345_i2c_read_p1_reg(client, DP_INT_STA, &val);
udelay(10);
}
/* Clear interrupt source for AUX CH command redply */
anx6345_i2c_write_p1_reg(client, DP_INT_STA, &val);
/* Check AUX CH error access status */
anx6345_i2c_read_p0_reg(client, AUX_CH_STA, &val);
if ((val & AUX_STATUS_MASK) != 0) {
dev_err(&client->dev, "AUX CH error happens: %d\n\n",
val & AUX_STATUS_MASK);
return -EREMOTEIO;
}
return retval;
}
int anx6345_dpcd_write_bytes(struct i2c_client *client,
unsigned int val_addr,
unsigned int count,
unsigned char data[])
{
char val;
unsigned int start_offset;
unsigned int cur_data_count;
unsigned int cur_data_idx;
int retval = 0;
start_offset = 0;
while (start_offset < count) {
/* Buffer size of AUX CH is 16 * 4bytes */
if ((count - start_offset) > 16)
cur_data_count = 16;
else
cur_data_count = count - start_offset;
val = BUF_CLR;
anx6345_i2c_write_p0_reg(client, BUF_DATA_CTL, &val);
val = AUX_ADDR_7_0(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
val = AUX_ADDR_15_8(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
val = AUX_ADDR_19_16(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
cur_data_idx++) {
val = data[start_offset + cur_data_idx];
anx6345_i2c_write_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
}
/*
* Set DisplayPort transaction and write
* If bit 3 is 1, DisplayPort transaction.
* If Bit 3 is 0, I2C transaction.
*/
val = AUX_LENGTH(cur_data_count) |
AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
/* Start AUX transaction */
retval = anx6345_start_aux_transaction(client);
if (retval == 0)
break;
else
dev_dbg(&client->dev, "Aux Transaction fail!\n");
start_offset += cur_data_count;
}
return retval;
}
int anx6345_dpcd_read_bytes(struct i2c_client *client,
unsigned int val_addr,
unsigned int count,
unsigned char data[])
{
char val;
unsigned int start_offset;
unsigned int cur_data_count;
unsigned int cur_data_idx;
int i;
int retval = 0;
start_offset = 0;
while (start_offset < count) {
/* Buffer size of AUX CH is 16 * 4bytes */
if ((count - start_offset) > 16)
cur_data_count = 16;
else
cur_data_count = count - start_offset;
/* AUX CH Request Transaction process */
for (i = 0; i < 10; i++) {
/* Select DPCD device address */
val = AUX_ADDR_7_0(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
val = AUX_ADDR_15_8(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
val = AUX_ADDR_19_16(val_addr + start_offset);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
/*
* Set DisplayPort transaction and read
* If bit 3 is 1, DisplayPort transaction.
* If Bit 3 is 0, I2C transaction.
*/
val = AUX_LENGTH(cur_data_count) |
AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
val = BUF_CLR;
anx6345_i2c_write_p0_reg(client, BUF_DATA_CTL, &val);
/* Start AUX transaction */
retval = anx6345_start_aux_transaction(client);
if (retval == 0)
break;
else
dev_dbg(&client->dev, "Aux Transaction fail!\n");
}
for (cur_data_idx = 0; cur_data_idx < cur_data_count;
cur_data_idx++) {
anx6345_i2c_read_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
data[start_offset + cur_data_idx] = val;
dev_dbg(&client->dev, "0x%05x :0x%02x\n",cur_data_idx, val);
}
start_offset += cur_data_count;
}
return retval;
}
int anx6345_select_i2c_device(struct i2c_client *client,
unsigned int device_addr,
char val_addr)
{
char val;
int retval;
/* Set normal AUX CH command */
anx6345_i2c_read_p0_reg(client, DP_AUX_CH_CTL_2, &val);
val &= ~ADDR_ONLY;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_2, &val);
/* Set EDID device address */
val = device_addr;
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_7_0, &val);
val = 0;
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_15_8, &val);
anx6345_i2c_write_p0_reg(client, DP_AUX_ADDR_19_16, &val);
/* Set offset from base address of EDID device */
anx6345_i2c_write_p0_reg(client, BUF_DATA_0, &val_addr);
/*
* Set I2C transaction and write address
* If bit 3 is 1, DisplayPort transaction.
* If Bit 3 is 0, I2C transaction.
*/
val = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
AUX_TX_COMM_WRITE;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
/* Start AUX transaction */
retval = anx6345_start_aux_transaction(client);
if (retval != 0)
dev_dbg(&client->dev, "Aux Transaction fail!\n");
return retval;
}
int anx6345_edid_read_bytes(struct i2c_client *client,
unsigned int device_addr,
unsigned int val_addr,
unsigned char count,
unsigned char edid[])
{
char val;
unsigned int i;
unsigned int start_offset;
unsigned int cur_data_idx;
unsigned int cur_data_cnt;
unsigned int defer = 0;
int retval = 0;
for (i = 0; i < count; i += 16) {
start_offset = i;
if ((count - start_offset) > 16)
cur_data_cnt = 16;
else
cur_data_cnt = count - start_offset;
/*
* If Rx sends defer, Tx sends only reads
* request without sending addres
*/
if (!defer)
retval = anx6345_select_i2c_device(client,
device_addr, val_addr + i);
else
defer = 0;
/*
* Set I2C transaction and write data
* If bit 3 is 1, DisplayPort transaction.
* If Bit 3 is 0, I2C transaction.
*/
val = AUX_LENGTH(cur_data_cnt) | AUX_TX_COMM_I2C_TRANSACTION |
AUX_TX_COMM_READ;
anx6345_i2c_write_p0_reg(client, DP_AUX_CH_CTL_1, &val);
/* Start AUX transaction */
retval = anx6345_start_aux_transaction(client);
if (retval < 0)
dev_dbg(&client->dev, "Aux Transaction fail!\n");
/* Check if Rx sends defer */
anx6345_i2c_read_p0_reg(client, DP_AUX_RX_COMM, &val);
if (val == AUX_RX_COMM_AUX_DEFER ||
val == AUX_RX_COMM_I2C_DEFER) {
dev_err(&client->dev, "Defer: %d\n\n", val);
defer = 1;
}
for (cur_data_idx = 0; cur_data_idx < cur_data_cnt; cur_data_idx++) {
anx6345_i2c_read_p0_reg(client, BUF_DATA_0 + cur_data_idx, &val);
edid[i + cur_data_idx] = val;
dev_dbg(&client->dev, "0x%02x : 0x%02x\n", i + cur_data_idx, val);
}
}
return retval;
}
static int anx6345_read_edid(struct i2c_client *client)
{
unsigned char edid[EDID_LENGTH * 2];
unsigned char extend_block = 0;
unsigned char sum;
unsigned char test_vector;
int retval;
char addr;
struct edp_anx6345 *anx6345 = i2c_get_clientdata(client);
/* Read Extension Flag, Number of 128-byte EDID extension blocks */
retval = anx6345_edid_read_bytes(client, EDID_ADDR,
EDID_EXTENSION_FLAG,1,&extend_block);
if (retval < 0) {
dev_err(&client->dev, "EDID extension flag failed!\n");
return -EIO;
}
if (extend_block > 0) {
dev_dbg(&client->dev, "EDID data includes a single extension!\n");
/* Read EDID data */
retval = anx6345_edid_read_bytes(client, EDID_ADDR,
EDID_HEADER,
EDID_LENGTH,
&edid[EDID_HEADER]);
if (retval != 0) {
dev_err(&client->dev, "EDID Read failed!\n");
return -EIO;
}
sum = edp_calc_edid_check_sum(edid);
if (sum != 0) {
dev_warn(&client->dev, "EDID bad checksum!\n");
return 0;
}
/* Read additional EDID data */
retval = anx6345_edid_read_bytes(client, EDID_ADDR, EDID_LENGTH,
EDID_LENGTH, &edid[EDID_LENGTH]);
if (retval != 0) {
dev_err(&client->dev, "EDID Read failed!\n");
return -EIO;
}
sum = edp_calc_edid_check_sum(&edid[EDID_LENGTH]);
if (sum != 0) {
dev_warn(&client->dev, "EDID bad checksum!\n");
return 0;
}
retval = anx6345_dpcd_read_bytes(client, DPCD_TEST_REQUEST,
1, &test_vector);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID Read failed!\n");
return retval;
}
if (test_vector & DPCD_TEST_EDID_READ) {
retval = anx6345_dpcd_write_bytes(client,
DPCD_TEST_EDID_CHECKSUM,1,
&edid[EDID_LENGTH + EDID_CHECKSUM]);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID Write failed!\n");
return retval;
}
addr = DPCD_TEST_EDID_CHECKSUM_WRITE;
retval = anx6345_dpcd_write_bytes(client,
DPCD_TEST_RESPONSE, 1, &addr);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID checksum failed!\n");
return retval;
}
}
} else {
dev_info(&client->dev, "EDID data does not include any extensions.\n");
/* Read EDID data */
retval = anx6345_edid_read_bytes(client, EDID_ADDR, EDID_HEADER,
EDID_LENGTH, &edid[EDID_HEADER]);
if (retval != 0) {
dev_err(&client->dev, "EDID Read failed!\n");
return -EIO;
}
sum = edp_calc_edid_check_sum(edid);
if (sum != 0) {
dev_warn(&client->dev, "EDID bad checksum!\n");
return 0;
}
retval = anx6345_dpcd_read_bytes(client, DPCD_TEST_REQUEST,
1,&test_vector);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID Read failed!\n");
return retval;
}
if (test_vector & DPCD_TEST_EDID_READ) {
retval = anx6345_dpcd_write_bytes(client,
DPCD_TEST_EDID_CHECKSUM, 1,
&edid[EDID_CHECKSUM]);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID Write failed!\n");
return retval;
}
addr = DPCD_TEST_EDID_CHECKSUM_WRITE;
retval = anx6345_dpcd_write_bytes(client, DPCD_TEST_RESPONSE,
1, &addr);
if (retval < 0) {
dev_err(&client->dev, "DPCD EDID checksum failed!\n");
return retval;
}
}
}
fb_edid_to_monspecs(edid, &anx6345->specs);
dev_info(&client->dev, "EDID Read success!\n");
return 0;
}
static int anx6345_init(struct i2c_client *client)
{
char val = 0x00;
char i = 0;
char lc,bw;
char cnt = 50;
u8 buf[12];
val = 0x30;
anx6345_i2c_write_p1_reg(client,SP_POWERD_CTRL_REG,&val);
printk("Init IN \n");
//clock detect
for(i=0;i<50;i++)
{
anx6345_i2c_read_p0_reg(client, SYS_CTRL1_REG, &val);
anx6345_i2c_write_p0_reg(client, SYS_CTRL1_REG, &val);
anx6345_i2c_read_p0_reg(client, SYS_CTRL1_REG, &val);
if((val&SYS_CTRL1_DET_STA)!=0)
{
break;
}
mdelay(10);
}
if(i>49)
printk("no clock detected by anx6345\n");
//check whether clock is stable
for(i=0;i<50;i++)
{
anx6345_i2c_read_p0_reg(client, SYS_CTRL2_REG, &val);
anx6345_i2c_write_p0_reg(client,SYS_CTRL2_REG, &val);
anx6345_i2c_read_p0_reg(client, SYS_CTRL2_REG, &val);
if((val&SYS_CTRL2_CHA_STA)==0)
{
break;
}
mdelay(10);
}
if(i>49)
printk("clk is not stable\n");
anx6345_dpcd_read_bytes(client, DPCD_REV, 12, buf);
anx6345_read_edid(client);
//VESA range, 6bits BPC, RGB
val = 0x00;
anx6345_i2c_write_p1_reg(client, VID_CTRL2_REG, &val);
//ANX6345 chip pll setting
val = 0x00;
anx6345_i2c_write_p0_reg(client, PLL_CTRL_REG, &val); //UPDATE: FROM 0X07 TO 0X00
//ANX chip analog setting
val = 0x70;
anx6345_i2c_write_p1_reg(client, ANALOG_DEBUG_REG1, &val); //UPDATE: FROM 0XF0 TO 0X70
val = 0x30;
anx6345_i2c_write_p0_reg(client, LINK_DEBUG_REG, &val);
//force HPD
//anx6345_i2c_write_p0_reg(client, SYS_CTRL3_REG, &val);
//reset AUX
anx6345_i2c_read_p1_reg(client, RST_CTRL2_REG, &val);
val |= AUX_RST;
anx6345_i2c_write_p1_reg(client, RST_CTRL2_REG, &val);
val &= ~AUX_RST;
anx6345_i2c_write_p1_reg(client, RST_CTRL2_REG, &val);
//Select 2.7G
val = 0x0a;
anx6345_i2c_write_p0_reg(client, LINK_BW_SET_REG, &val);
//Select 2 lanes
val = 0x01;
anx6345_i2c_write_p0_reg(client,LANE_COUNT_SET_REG,&val);
val = LINK_TRAINING_CTRL_EN;
anx6345_i2c_write_p0_reg(client, LINK_TRAINING_CTRL_REG, &val);
mdelay(5);
anx6345_i2c_read_p0_reg(client, LINK_TRAINING_CTRL_REG, &val);
while((val&0x80)&&(cnt)) //UPDATE: FROM 0X01 TO 0X80
{
printk("Waiting...\n");
mdelay(5);
anx6345_i2c_read_p0_reg(client,LINK_TRAINING_CTRL_REG,&val);
cnt--;
}
if(cnt <= 0)
{
printk(KERN_INFO "HW LT fail\n");
}
else
printk("HW LT Success>>:times:%d\n",(51-cnt));
//enable video input, set DDR mode, the input DCLK should be 102.5MHz;
//In normal mode, set this reg to 0x81, SDR mode, the input DCLK should be 205MHz
val = 0x80;
anx6345_i2c_write_p1_reg(client,VID_CTRL1_REG,&val);
anx_video_map_config(client);
//force HPD and stream valid
val = 0x33; //0x33
anx6345_i2c_write_p0_reg(client,SYS_CTRL3_REG,&val);
lc=1;
bw=0x0a;
anx6345_i2c_read_p0_reg(client,LANE_COUNT_SET_REG, &lc);
anx6345_i2c_read_p0_reg(client,LINK_BW_SET_REG, &bw);
printk("%s..lc:%d--bw:%d\n",__func__,lc,bw);
return 0;
}
static int anx6345_disable(void)
{
struct edp_anx6345 *anx6345 = edp;
if (!anx6345->pdata->pwron)
return 0;
// gpio_set_value(anx6345->pdata->dvdd33_en_pin,!anx6345->pdata->dvdd33_en_val);
// gpio_set_value(anx6345->pdata->dvdd18_en_pin,!anx6345->pdata->dvdd18_en_val);
anx6345->pdata->pwron = false;
return 0;
}
static int anx6345_enable(void)
{
struct edp_anx6345 *anx6345 = edp;
if (!anx6345->pdata->pwron) {
//gpio_set_value(anx6345->pdata->dvdd33_en_pin,anx6345->pdata->dvdd33_en_val);
msleep(5);
//gpio_set_value(anx6345->pdata->dvdd18_en_pin,anx6345->pdata->dvdd18_en_val);
//gpio_set_value(anx6345->pdata->edp_rst_pin,0);
msleep(50);
//gpio_set_value(anx6345->pdata->edp_rst_pin,1);
anx6345->pdata->pwron = true;
}
anx6345->edp_anx_init(anx6345->client);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void anx6345_early_suspend(struct early_suspend *h)
{
anx6345_disable();
}
static void anx6345_late_resume(struct early_suspend *h)
{
anx6345_enable();
}
#endif
#if defined(CONFIG_OF)
static int anx6345_power_ctl(struct anx6345_platform_data *pdata)
{
int ret;
//ret = gpio_request(pdata->dvdd33_en_pin, "dvdd33_en_pin");
pdata->pwron = true;
return 0;
}
/*
struct rk_fb_trsm_ops trsm_edp_ops = {
.enable = anx6345_enable,
.disable = anx6345_disable,
};
*/
static void anx6345_parse_dt(struct edp_anx6345 *anx6345)
{
struct device_node *np = anx6345->client->dev.of_node;
struct anx6345_platform_data *pdata;
//enum of_gpio_flags dvdd33_flags,dvdd18_flags,rst_flags;
pdata = kzalloc(
sizeof(struct anx6345_platform_data ), GFP_KERNEL);
if (!pdata) {
dev_err(&anx6345->client->dev,
"failed to allocate platform data\n");
return ;
}
// pdata->dvdd33_en_pin = of_get_named_gpio_flags(np, "dvdd33-gpio", 0, &dvdd33_flags);
// pdata->dvdd18_en_pin = of_get_named_gpio_flags(np, "dvdd18-gpio", 0, &dvdd18_flags);
// pdata->edp_rst_pin = of_get_named_gpio_flags(np, "reset-gpio", 0, &rst_flags);
// pdata->dvdd33_en_val = (dvdd33_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
// pdata->dvdd18_en_val = (dvdd18_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
// pdata->power_ctl = anx6345_power_ctl;
anx6345->pdata = pdata;
}
#else
static void anx6345_parse_dt(struct edp_anx6345 * anx6345)
{
}
#endif
static int anx6345_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
struct edp_anx6345 *anx6345 = NULL;
int chip_id,ret;
printk("Probe Enter!!!\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");
ret = -ENODEV;
}
anx6345 = kzalloc(sizeof(struct edp_anx6345), GFP_KERNEL);
if (anx6345 == NULL)
{
printk("alloc for struct anx6345 fail\n");
ret = -ENOMEM;
}
client->addr = 0x39;
anx6345->client = client;
anx6345->pdata = client->dev.platform_data;
i2c_set_clientdata(client,anx6345);
printk("Probe Enter get id!!!\n");
anx6345->edp_anx_init = anx6345_init;
printk("Probe Enter edp_anx_init!!!\n");
anx6345->edp_anx_init(client);
printk("edp anx%x probe ok\n",get_dp_chip_id(client));
return ret;
}
static int anx6345_i2c_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id id_table[] = {
{"anx6345", 0 },
{ }
};
#if defined(CONFIG_OF)
static struct of_device_id anx6345_dt_ids[] = {
{ .compatible = "analogix, anx6345" },
{ }
};
#endif
static struct i2c_driver anx6345_i2c_driver = {
.driver = {
.name = "anx6345",
.owner = THIS_MODULE,
#if defined(CONFIG_OF)
.of_match_table = of_match_ptr(anx6345_dt_ids),
#endif
},
.probe = &anx6345_i2c_probe,
.remove = &anx6345_i2c_remove,
.id_table = id_table,
};
static int __init anx6345_module_init(void)
{
printk("anx6345 Init Ret: \n");
return i2c_add_driver(&anx6345_i2c_driver);
}
static void __exit anx6345_module_exit(void)
{
i2c_del_driver(&anx6345_i2c_driver);
}
module_exit(anx6345_module_exit);
module_init(anx6345_module_init);
MODULE_AUTHOR("Mitko Gamishev <hehopmajieh@debian.bg>");
MODULE_DESCRIPTION("AN6345 RGB<->eDP Transmitter");
MODULE_LICENSE("GPL");