From: Xuhua Zhang Date: Mon, 26 Jun 2017 07:44:23 +0000 (+0800) Subject: i2c: add i2c auto test and fix i2c clk error. X-Git-Tag: khadas-vims-v0.9.6-release~2971 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b63832bae3821ddf143ddbcc7e637a30344de9e4;p=platform%2Fkernel%2Flinux-amlogic.git i2c: add i2c auto test and fix i2c clk error. PD#146534: add i2c auto test and fix i2c clk error. 1. add i2c auto test function form 50KHZ to 3.4MHZ. 2. fix i2c clk distortion when the clk go beyond 1MHZ. 3. fix i2c clk distortion when the clk less than 100KHZ. 4. fit for i2c T_low/T_higt time standard. 5. reduce i2c error log. Change-Id: I2bb5598684848478aa18349b87eaac5bcc44065d Signed-off-by: Xuhua Zhang --- diff --git a/drivers/amlogic/i2c/aml_master.c b/drivers/amlogic/i2c/aml_master.c index 4e0b2a7..9aa34f8 100644 --- a/drivers/amlogic/i2c/aml_master.c +++ b/drivers/amlogic/i2c/aml_master.c @@ -56,6 +56,12 @@ static struct aml_i2c_platform *aml_i2c_properties_list; static int i2c_speed[] = {AML_I2C_SPEED_50K, AML_I2C_SPEED_100K, AML_I2C_SPEED_200K, AML_I2C_SPEED_300K, AML_I2C_SPEED_400K}; +#define I2C_COUNTERVAIL 14 +static const int auto_test_speed[] = {AML_I2C_SPEED_50K, AML_I2C_SPEED_100K, + AML_I2C_SPEED_200K, AML_I2C_SPEED_300K, AML_I2C_SPEED_400K, + AML_I2C_SPEED_1000K, AML_I2C_SPEED_2000K, AML_I2C_SPEED_3000K, + AML_I2C_SPEED_3400K}; + #define aml_i2c_dbg(i2c, fmt, args...) { if (i2c->i2c_debug) \ pr_info("[i2c@%d] " fmt, i2c->master_no, ## args); } #define aml_i2c_dump(i2c) \ @@ -79,6 +85,7 @@ static void aml_i2c_set_clk(struct aml_i2c *i2c, unsigned int speed) { unsigned int i2c_clock_set; unsigned int sys_clk_rate; + unsigned int i2c_standard_time; /* struct clk *sys_clk; */ struct aml_i2c_reg_ctrl *ctrl; @@ -88,25 +95,34 @@ static void aml_i2c_set_clk(struct aml_i2c *i2c, unsigned int speed) /* sys_clk_rate = get_mpeg_clk(); */ i2c_clock_set = sys_clk_rate / speed; + + /*i2c_standard_time: set for i2c T_high/T_low standard*/ + if (speed >= 1000000) + i2c_standard_time = 5; + else + i2c_standard_time = 20; if (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MAJOR) > MESON_CPU_MAJOR_ID_GXBB) { i2c_clock_set >>= 1; ctrl = (struct aml_i2c_reg_ctrl *)&(i2c->master_regs->i2c_ctrl); if (i2c_clock_set > 0xfff) i2c_clock_set = 0xfff; - ctrl->clk_delay = i2c_clock_set & 0x3ff; - ctrl->unused.b.clk_delay_ext = i2c_clock_set >> 10; + + ctrl->clk_delay = + (i2c_clock_set - I2C_COUNTERVAIL - i2c_standard_time*2) & 0x3ff; + ctrl->clk_delay_ext = + (i2c_clock_set - I2C_COUNTERVAIL - i2c_standard_time*2) >> 10; i2c->master_regs->i2c_slave_addr &= ~(0xfff<<16); - i2c->master_regs->i2c_slave_addr |= (i2c_clock_set>>1)<<16; + i2c->master_regs->i2c_slave_addr |= + ((i2c_clock_set>>1) + i2c_standard_time)<<16; i2c->master_regs->i2c_slave_addr |= 1<<28; i2c->master_regs->i2c_slave_addr &= ~(0x3f<<8); /* no filter on scl&sda */ } else{ i2c_clock_set >>= 2; - - ctrl = (struct aml_i2c_reg_ctrl *)&(i2c->master_regs->i2c_ctrl); - ctrl->clk_delay = i2c_clock_set & AML_I2C_CTRL_CLK_DELAY_MASK; -} + ctrl = (struct aml_i2c_reg_ctrl *)&(i2c->master_regs->i2c_ctrl); + ctrl->clk_delay = i2c_clock_set & AML_I2C_CTRL_CLK_DELAY_MASK; + } } static void aml_i2c_set_platform_data(struct aml_i2c *i2c, @@ -254,6 +270,7 @@ static long aml_i2c_do_address(struct aml_i2c *i2c, unsigned int addr) i2c->master_regs->i2c_slave_addr |= i2c->cur_slave_addr<<1; } else i2c->master_regs->i2c_slave_addr = i2c->cur_slave_addr<<1; + return 0; } @@ -562,6 +579,8 @@ static int aml_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, { struct aml_i2c *i2c = i2c_get_adapdata(i2c_adap); struct i2c_msg *p = NULL; + static int local_err_i2c = 1; + static int pre_err_i2c = 1; unsigned int i; unsigned int ret = 0, speed = 0; @@ -618,15 +637,19 @@ static int aml_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, gpiod_direction_output(i2c->i2c_gdesc, !i); } #endif - dev_err(&i2c_adap->dev, - "[aml_i2c_xfer] error ret = %d (%s)", - ret, ret == -EIO ? "-EIO" : "-ETIMEOUT"); - dev_err(&i2c_adap->dev, - "token %d, master_no(%d) %dK addr 0x%x\n", - i2c->cur_token, i2c->master_no, - i2c->master_i2c_speed/1000, - i2c->cur_slave_addr); - aml_i2c_dump(i2c); + local_err_i2c = i2c->cur_slave_addr; + if (pre_err_i2c != local_err_i2c) { + dev_err(&i2c_adap->dev, + "[aml_i2c_xfer] error ret = %d (%s)", + ret, ret == -EIO ? "-EIO" : "-ETIMEOUT"); + dev_err(&i2c_adap->dev, + "token %d, master_no(%d) %dK addr 0x%x\n", + i2c->cur_token, i2c->master_no, + i2c->master_i2c_speed/1000, + i2c->cur_slave_addr); + aml_i2c_dump(i2c); + } + pre_err_i2c = local_err_i2c; } mutex_unlock(i2c->lock); @@ -773,11 +796,8 @@ static int aml_i2c_auto_test(struct aml_i2c *i2c, unsigned int val) msg_num++; } - if (i2c_transfer(&i2c->adap, &msgs, msg_num) != msg_num) { - pr_info("i2c auto test failed at speed %d KHZ!\n", - (i2c->master_i2c_speed)/1000); + if (i2c_transfer(&i2c->adap, &msgs, msg_num) != msg_num) return -1; - } msleep(200); msg_num = 0; @@ -803,16 +823,12 @@ static int aml_i2c_auto_test(struct aml_i2c *i2c, unsigned int val) if (i2c_transfer(&i2c->adap, &msgx[0], msg_num) == msg_num) { for (i = 0; i < rnum; i++) { if (wbuf1[i+1] != rbuf[i]) { - pr_info("i2c auto test failed 1 at speed %d KHZ!\n", - (i2c->master_i2c_speed)/1000); + pr_info("i2c auto test receive buff error!\n"); return -1; } } - } else { - pr_info("i2c auto test failed 2 at speed %d KHZ!\n", - (i2c->master_i2c_speed)/1000); + } else return -1; - } msleep(200); /* fill up default date*/ @@ -828,8 +844,27 @@ static int aml_i2c_auto_test(struct aml_i2c *i2c, unsigned int val) return -1; msleep(100); - pr_info("I2C auto test master and slave ok! speed = %d KHZ!\n", - (i2c->master_i2c_speed)/1000); + return 0; +} + +static int aml_i2c_auto_test_loop(struct aml_i2c *i2c, unsigned int val) +{ + int i, ret; + int num = ARRAY_SIZE(auto_test_speed); + + for (i = 0; i < num; i++) { + mutex_lock(i2c->lock); + i2c->master_i2c_speed = auto_test_speed[i]; + mutex_unlock(i2c->lock); + ret = aml_i2c_auto_test(i2c, val); + if (ret < 0) { + pr_info("i2c auto test error at %d KHZ\n", + auto_test_speed[i]/1000); + return -1; + } + pr_info("i2c speed %d KHZ test ok!\n", auto_test_speed[i]/1000); + } + pr_info("I2C auto test master and slave ok!\n"); return 0; } @@ -937,11 +972,7 @@ static ssize_t store_aml_i2c(struct class *class, } else if (!strcmp(attr->attr.name, "auto_test")) { - mutex_lock(i2c->lock); - i2c->master_i2c_speed = val; - mutex_unlock(i2c->lock); - //pr_info("set speed: %d\n", i2c->master_i2c_speed); - aml_i2c_auto_test(i2c, val2); + aml_i2c_auto_test_loop(i2c, val); } else if (!strcmp(attr->attr.name, "slave")) { @@ -1147,7 +1178,7 @@ static int aml_i2c_probe(struct platform_device *pdev) if (i2c->adap.nr) sprintf((char *)i2c->cls.name, "i2c%d", i2c->adap.nr); else - sprintf((char *)i2c->cls.name, "i2c"); + sprintf((char *)i2c->cls.name, "i2c0"); i2c->cls.class_attrs = i2c_class_attrs; ret = class_register(&i2c->cls); if (ret) diff --git a/drivers/amlogic/i2c/aml_master.h b/drivers/amlogic/i2c/aml_master.h index 0d5dc53..1eb7701 100644 --- a/drivers/amlogic/i2c/aml_master.h +++ b/drivers/amlogic/i2c/aml_master.h @@ -49,14 +49,6 @@ } \ } while (0) -union unused { - struct{ - unsigned int unused:1; /*[27]*/ - unsigned int clk_delay_ext:2; /*[29:28]*/ - unsigned int unused2:2; /*[31:30]*/ - } b; - unsigned int unused:5; /*[31:27]*/ - } unused; /*I2C_CONTROL_REG 0x2140*/ struct aml_i2c_reg_ctrl { unsigned int start:1; /*[0] */ @@ -134,7 +126,9 @@ struct aml_i2c_reg_ctrl { */ unsigned int rdscl:1; /*[25] Read back level of the SCL line*/ unsigned int rdsda:1; /*[26] Read back level of the SDA line*/ - union unused unused; + unsigned int unused:1; /*[27]*/ + unsigned int clk_delay_ext:2; /*[29:28]*/ + unsigned int unused2:2; /*[31:30]*/ }; union unused2 { diff --git a/drivers/amlogic/i2c/aml_slave.c b/drivers/amlogic/i2c/aml_slave.c index a19b091..cad76fd 100644 --- a/drivers/amlogic/i2c/aml_slave.c +++ b/drivers/amlogic/i2c/aml_slave.c @@ -50,7 +50,7 @@ struct aml_i2c_slave *slave) slave->slave_regs->s_reg_ctrl |= (1<<27);/*recv en*/ slave->slave_regs->s_reg_ctrl |= (0x40<<16); /*slave addr*/ slave->slave_regs->s_reg_ctrl |= (0x0<<8); /*hold time*/ - slave->slave_regs->s_reg_ctrl |= (0x6); /*sampling rate*/ + slave->slave_regs->s_reg_ctrl |= (0x0<<0); /*sampling rate*/ } static ssize_t show_i2c_slave(struct class *class, diff --git a/include/linux/amlogic/i2c-amlogic.h b/include/linux/amlogic/i2c-amlogic.h index 1fd4516..d151624 100644 --- a/include/linux/amlogic/i2c-amlogic.h +++ b/include/linux/amlogic/i2c-amlogic.h @@ -22,6 +22,10 @@ #define AML_I2C_SPEED_200K 200000 #define AML_I2C_SPEED_300K 300000 #define AML_I2C_SPEED_400K 400000 +#define AML_I2C_SPEED_1000K 1000000 +#define AML_I2C_SPEED_2000K 2000000 +#define AML_I2C_SPEED_3000K 3000000 +#define AML_I2C_SPEED_3400K 3400000 #define AML_I2C_MASTER_AO 0 #define AML_I2C_MASTER_A 1