blob: f9fc75d4a2e24e9fd9d052768dd9dd1550dae242 [file] [log] [blame]
Edward A. James7bd86372017-05-15 12:28:44 -05001From patchwork Wed May 10 15:52:41 2017
2Content-Type: text/plain; charset="utf-8"
3MIME-Version: 1.0
4Content-Transfer-Encoding: 7bit
5Subject: [linux, dev-4.10, v2,
6 5/6] drivers: i2c: Add bus recovery for FSI algorithm
7From: eajames@linux.vnet.ibm.com
8X-Patchwork-Id: 760701
9Message-Id: <1494431562-25101-6-git-send-email-eajames@linux.vnet.ibm.com>
10To: openbmc@lists.ozlabs.org
11Cc: "Edward A. James" <eajames@us.ibm.com>, cbostic@linux.vnet.ibm.com
12Date: Wed, 10 May 2017 10:52:41 -0500
13
14From: "Edward A. James" <eajames@us.ibm.com>
15
16Bus recovery should reset the engine and force block the bus 9 times
17to recover most situations.
18
19Signed-off-by: Edward A. James <eajames@us.ibm.com>
20---
21 drivers/i2c/busses/i2c-fsi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
22 1 file changed, 76 insertions(+)
23
24diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
25index d757aee..4689479 100644
26--- a/drivers/i2c/busses/i2c-fsi.c
27+++ b/drivers/i2c/busses/i2c-fsi.c
28@@ -467,6 +467,80 @@ static u32 fsi_i2c_functionality(struct i2c_adapter *adap)
29 return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_10BIT_ADDR;
30 }
31
32+static int fsi_i2c_low_level_recover_bus(struct fsi_i2c_master *i2c)
33+{
34+ int i, rc;
35+ u32 mode, dummy = 0;
36+
37+ rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode);
38+ if (rc)
39+ return rc;
40+
41+ mode |= I2C_MODE_DIAG;
42+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
43+ if (rc)
44+ return rc;
45+
46+ for (i = 0; i < 9; ++i) {
47+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
48+ if (rc)
49+ return rc;
50+
51+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
52+ if (rc)
53+ return rc;
54+ }
55+
56+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SCL, &dummy);
57+ if (rc)
58+ return rc;
59+
60+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_SDA, &dummy);
61+ if (rc)
62+ return rc;
63+
64+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy);
65+ if (rc)
66+ return rc;
67+
68+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy);
69+ if (rc)
70+ return rc;
71+
72+ mode &= ~I2C_MODE_DIAG;
73+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
74+
75+ return rc;
76+}
77+
78+static int fsi_i2c_recover_bus(struct i2c_adapter *adap)
79+{
80+ int rc;
81+ u32 dummy = 0;
82+ struct fsi_i2c_port *port = adap->algo_data;
83+ struct fsi_i2c_master *i2c = port->master;
84+
85+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_I2C, &dummy);
86+ if (rc)
87+ return rc;
88+
89+ rc = fsi_i2c_dev_init(i2c);
90+ if (rc)
91+ return rc;
92+
93+ rc = fsi_i2c_low_level_recover_bus(i2c);
94+ if (rc)
95+ return rc;
96+
97+ rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_RESET_ERR, &dummy);
98+
99+ return rc;
100+}
101+
102+static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = {
103+ .recover_bus = fsi_i2c_recover_bus,
104+};
105+
106 static const struct i2c_algorithm fsi_i2c_algorithm = {
107 .master_xfer = fsi_i2c_xfer,
108 .functionality = fsi_i2c_functionality,
109@@ -514,6 +588,8 @@ static int fsi_i2c_probe(struct device *dev)
110 port->adapter.owner = THIS_MODULE;
111 port->adapter.dev.parent = dev;
112 port->adapter.algo = &fsi_i2c_algorithm;
113+ port->adapter.bus_recovery_info =
114+ &fsi_i2c_bus_recovery_info;
115 port->adapter.algo_data = port;
116 /* number ports uniquely */
117 port->adapter.nr = (i2c->idx * I2C_MASTER_NR_OFFSET) +