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 Side-by-side Diff

arch/arm/mach-imx/i2c-mxv7.c
1 1 /*
2 2 * Copyright (C) 2012 Boundary Devices Inc.
  3 + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
  4 + * Copyright 2018 NXP
3 5 *
4 6 * SPDX-License-Identifier: GPL-2.0+
5 7 */
6 8  
7 9  
8 10  
... ... @@ -33,13 +35,36 @@
33 35  
34 36 printf("%s: sda=%d scl=%d sda.gp=0x%x scl.gp=0x%x\n", __func__,
35 37 sda, scl, p->sda.gp, p->scl.gp);
  38 + gpio_direction_output(p->scl.gp, 1);
  39 + udelay(1000);
36 40 /* Send high and low on the SCL line */
37 41 for (i = 0; i < 9; i++) {
  42 + gpio_direction_output(p->scl.gp, 1);
  43 + udelay(50);
38 44 gpio_direction_output(p->scl.gp, 0);
39 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 68 start_time = get_timer(0);
44 69 for (;;) {
45 70 sda = gpio_get_value(p->sda.gp);