Commit 6220bb6fb43aa485a10f96fb6ade864b3371e4ca

Authored by Ye Li
1 parent db7ae71814

ENGR00328312 i2c: imx: Optimize the i2c device recovery solution

From i2c spec, if device pull down the SDA line that causes
i2c bus dead, host can send out 9 clock to let device release
SDA.

But for some special device like pfuze100, it pull down SDA line
and the solution cannot take effort.

The patch just add NACK and STOP signal after 8 dummy clock, and pmic
can release SDA line after the recovery. Test case catch 375 times of
i2c hang, and all are recovered.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Peng Fan <Peng.Fan@freescale.com>
Signed-off-by: Ye Li <ye.li@nxp.com>

Showing 1 changed file with 27 additions and 2 deletions Inline Diff

arch/arm/mach-imx/i2c-mxv7.c
1 /* 1 /*
2 * Copyright (C) 2012 Boundary Devices Inc. 2 * Copyright (C) 2012 Boundary Devices Inc.
3 * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
4 * Copyright 2018 NXP
3 * 5 *
4 * SPDX-License-Identifier: GPL-2.0+ 6 * SPDX-License-Identifier: GPL-2.0+
5 */ 7 */
6 #include <common.h> 8 #include <common.h>
7 #include <malloc.h> 9 #include <malloc.h>
8 #include <asm/arch/clock.h> 10 #include <asm/arch/clock.h>
9 #include <asm/arch/imx-regs.h> 11 #include <asm/arch/imx-regs.h>
10 #include <linux/errno.h> 12 #include <linux/errno.h>
11 #include <asm/gpio.h> 13 #include <asm/gpio.h>
12 #include <asm/mach-imx/mxc_i2c.h> 14 #include <asm/mach-imx/mxc_i2c.h>
13 #include <watchdog.h> 15 #include <watchdog.h>
14 16
15 int force_idle_bus(void *priv) 17 int force_idle_bus(void *priv)
16 { 18 {
17 int i; 19 int i;
18 int sda, scl; 20 int sda, scl;
19 ulong elapsed, start_time; 21 ulong elapsed, start_time;
20 struct i2c_pads_info *p = (struct i2c_pads_info *)priv; 22 struct i2c_pads_info *p = (struct i2c_pads_info *)priv;
21 int ret = 0; 23 int ret = 0;
22 24
23 gpio_direction_input(p->sda.gp); 25 gpio_direction_input(p->sda.gp);
24 gpio_direction_input(p->scl.gp); 26 gpio_direction_input(p->scl.gp);
25 27
26 imx_iomux_v3_setup_pad(p->sda.gpio_mode); 28 imx_iomux_v3_setup_pad(p->sda.gpio_mode);
27 imx_iomux_v3_setup_pad(p->scl.gpio_mode); 29 imx_iomux_v3_setup_pad(p->scl.gpio_mode);
28 30
29 sda = gpio_get_value(p->sda.gp); 31 sda = gpio_get_value(p->sda.gp);
30 scl = gpio_get_value(p->scl.gp); 32 scl = gpio_get_value(p->scl.gp);
31 if ((sda & scl) == 1) 33 if ((sda & scl) == 1)
32 goto exit; /* Bus is idle already */ 34 goto exit; /* Bus is idle already */
33 35
34 printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__, 36 printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
35 sda, scl, p->sda.gp, p->scl.gp); 37 sda, scl, p->sda.gp, p->scl.gp);
38 gpio_direction_output(p->scl.gp, 1);
39 udelay(1000);
36 /* Send high and low on the SCL line */ 40 /* Send high and low on the SCL line */
37 for (i = 0; i < 9; i++) { 41 for (i = 0; i < 9; i++) {
42 gpio_direction_output(p->scl.gp, 1);
43 udelay(50);
38 gpio_direction_output(p->scl.gp, 0); 44 gpio_direction_output(p->scl.gp, 0);
39 udelay(50); 45 udelay(50);
40 gpio_direction_input(p->scl.gp);
41 udelay(50);
42 } 46 }
47
48 /* Simulate the NACK */
49 gpio_direction_output(p->sda.gp, 1);
50 udelay(50);
51 gpio_direction_output(p->scl.gp, 1);
52 udelay(50);
53 gpio_direction_output(p->scl.gp, 0);
54 udelay(50);
55
56 /* Simulate the STOP signal */
57 gpio_direction_output(p->sda.gp, 0);
58 udelay(50);
59 gpio_direction_output(p->scl.gp, 1);
60 udelay(50);
61 gpio_direction_output(p->sda.gp, 1);
62 udelay(50);
63
64 /* Get the bus status */
65 gpio_direction_input(p->sda.gp);
66 gpio_direction_input(p->scl.gp);
67
43 start_time = get_timer(0); 68 start_time = get_timer(0);
44 for (;;) { 69 for (;;) {
45 sda = gpio_get_value(p->sda.gp); 70 sda = gpio_get_value(p->sda.gp);
46 scl = gpio_get_value(p->scl.gp); 71 scl = gpio_get_value(p->scl.gp);
47 if ((sda & scl) == 1) 72 if ((sda & scl) == 1)
48 break; 73 break;
49 WATCHDOG_RESET(); 74 WATCHDOG_RESET();
50 elapsed = get_timer(start_time); 75 elapsed = get_timer(start_time);
51 if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */ 76 if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */
52 ret = -EBUSY; 77 ret = -EBUSY;
53 printf("%s: failed to clear bus, sda=%d scl=%d\n", 78 printf("%s: failed to clear bus, sda=%d scl=%d\n",
54 __func__, sda, scl); 79 __func__, sda, scl);
55 break; 80 break;
56 } 81 }
57 } 82 }
58 exit: 83 exit:
59 imx_iomux_v3_setup_pad(p->sda.i2c_mode); 84 imx_iomux_v3_setup_pad(p->sda.i2c_mode);
60 imx_iomux_v3_setup_pad(p->scl.i2c_mode); 85 imx_iomux_v3_setup_pad(p->scl.i2c_mode);
61 return ret; 86 return ret;
62 } 87 }
63 88
64 static void * const i2c_bases[] = { 89 static void * const i2c_bases[] = {
65 (void *)I2C1_BASE_ADDR, 90 (void *)I2C1_BASE_ADDR,
66 (void *)I2C2_BASE_ADDR, 91 (void *)I2C2_BASE_ADDR,
67 #ifdef I2C3_BASE_ADDR 92 #ifdef I2C3_BASE_ADDR
68 (void *)I2C3_BASE_ADDR, 93 (void *)I2C3_BASE_ADDR,
69 #endif 94 #endif
70 #ifdef I2C4_BASE_ADDR 95 #ifdef I2C4_BASE_ADDR
71 (void *)I2C4_BASE_ADDR, 96 (void *)I2C4_BASE_ADDR,
72 #endif 97 #endif
73 }; 98 };
74 99
75 /* i2c_index can be from 0 - 3 */ 100 /* i2c_index can be from 0 - 3 */
76 int setup_i2c(unsigned i2c_index, int speed, int slave_addr, 101 int setup_i2c(unsigned i2c_index, int speed, int slave_addr,
77 struct i2c_pads_info *p) 102 struct i2c_pads_info *p)
78 { 103 {
79 char name[9]; 104 char name[9];
80 int ret; 105 int ret;
81 106
82 if (i2c_index >= ARRAY_SIZE(i2c_bases)) 107 if (i2c_index >= ARRAY_SIZE(i2c_bases))
83 return -EINVAL; 108 return -EINVAL;
84 109
85 snprintf(name, sizeof(name), "i2c_sda%01d", i2c_index); 110 snprintf(name, sizeof(name), "i2c_sda%01d", i2c_index);
86 ret = gpio_request(p->sda.gp, name); 111 ret = gpio_request(p->sda.gp, name);
87 if (ret) 112 if (ret)
88 return ret; 113 return ret;
89 114
90 snprintf(name, sizeof(name), "i2c_scl%01d", i2c_index); 115 snprintf(name, sizeof(name), "i2c_scl%01d", i2c_index);
91 ret = gpio_request(p->scl.gp, name); 116 ret = gpio_request(p->scl.gp, name);
92 if (ret) 117 if (ret)
93 goto err_req; 118 goto err_req;
94 119
95 /* Enable i2c clock */ 120 /* Enable i2c clock */
96 ret = enable_i2c_clk(1, i2c_index); 121 ret = enable_i2c_clk(1, i2c_index);
97 if (ret) 122 if (ret)
98 goto err_clk; 123 goto err_clk;
99 124
100 /* Make sure bus is idle */ 125 /* Make sure bus is idle */
101 ret = force_idle_bus(p); 126 ret = force_idle_bus(p);
102 if (ret) 127 if (ret)
103 goto err_idle; 128 goto err_idle;
104 129
105 #ifndef CONFIG_DM_I2C 130 #ifndef CONFIG_DM_I2C
106 bus_i2c_init(i2c_index, speed, slave_addr, force_idle_bus, p); 131 bus_i2c_init(i2c_index, speed, slave_addr, force_idle_bus, p);
107 #endif 132 #endif
108 133
109 return 0; 134 return 0;
110 135
111 err_idle: 136 err_idle:
112 err_clk: 137 err_clk:
113 gpio_free(p->scl.gp); 138 gpio_free(p->scl.gp);
114 err_req: 139 err_req:
115 gpio_free(p->sda.gp); 140 gpio_free(p->sda.gp);
116 141
117 return ret; 142 return ret;