Commit 8cae207d03cac19c57b135871493a9278948cc18
1 parent
95a530df83
Exists in
smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga
and in
5 other branches
MLK-17357-2 lpi2c: Add bus busy error handling
When doing "i2c dev 4; i2c probe" with ENET daughter card connected on iMX8QXP MEK board, we met a i2c bus busy issue, that the BBF of lpi2c always show busy, but the master is idle, and stop is detected (SDF set). This patch addes a handling to re-init the lpi2c master for this case. Then the issue can be worked around. Signed-off-by: Ye Li <ye.li@nxp.com> Acked-by: Peng Fan <peng.fan@nxp.com> (cherry picked from commit 6b4021d04c7f637fd60cf73f9cc46fdebc853790)
Showing 1 changed file with 30 additions and 21 deletions Side-by-side Diff
drivers/i2c/imx_lpi2c.c
... | ... | @@ -20,6 +20,8 @@ |
20 | 20 | #define LPI2C_NACK_TOUT_MS 1 |
21 | 21 | #define LPI2C_TIMEOUT_MS 100 |
22 | 22 | |
23 | +static int bus_i2c_init(struct udevice *bus, int speed); | |
24 | + | |
23 | 25 | /* Weak linked function for overridden by some SoC power function */ |
24 | 26 | int __weak init_i2c_power(unsigned i2c_num) |
25 | 27 | { |
26 | 28 | |
... | ... | @@ -93,8 +95,9 @@ |
93 | 95 | return result; |
94 | 96 | } |
95 | 97 | |
96 | -static int bus_i2c_send(struct imx_lpi2c_reg *regs, u8 *txbuf, int len) | |
98 | +static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len) | |
97 | 99 | { |
100 | + struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
98 | 101 | lpi2c_status_t result = LPI2C_SUCESS; |
99 | 102 | |
100 | 103 | /* empty tx */ |
101 | 104 | |
... | ... | @@ -113,8 +116,9 @@ |
113 | 116 | return result; |
114 | 117 | } |
115 | 118 | |
116 | -static int bus_i2c_receive(struct imx_lpi2c_reg *regs, u8 *rxbuf, int len) | |
119 | +static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len) | |
117 | 120 | { |
121 | + struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
118 | 122 | lpi2c_status_t result = LPI2C_SUCESS; |
119 | 123 | u32 val; |
120 | 124 | ulong start_time = get_timer(0); |
121 | 125 | |
122 | 126 | |
... | ... | @@ -155,15 +159,23 @@ |
155 | 159 | return result; |
156 | 160 | } |
157 | 161 | |
158 | -static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir) | |
162 | +static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir) | |
159 | 163 | { |
164 | + struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
160 | 165 | lpi2c_status_t result = LPI2C_SUCESS; |
161 | 166 | u32 val; |
162 | 167 | |
163 | 168 | result = imx_lpci2c_check_busy_bus(regs); |
164 | 169 | if (result) { |
165 | 170 | debug("i2c: start check busy bus: 0x%x\n", result); |
166 | - return result; | |
171 | + | |
172 | + /* Try to init the lpi2c then check the bus busy again */ | |
173 | + bus_i2c_init(bus, 100000); | |
174 | + result = imx_lpci2c_check_busy_bus(regs); | |
175 | + if (result) { | |
176 | + printf("i2c: Error check busy bus: 0x%x\n", result); | |
177 | + return result; | |
178 | + } | |
167 | 179 | } |
168 | 180 | /* clear all status flags */ |
169 | 181 | writel(0x7f00, ®s->msr); |
170 | 182 | |
... | ... | @@ -183,8 +195,9 @@ |
183 | 195 | return result; |
184 | 196 | } |
185 | 197 | |
186 | -static int bus_i2c_stop(struct imx_lpi2c_reg *regs) | |
198 | +static int bus_i2c_stop(struct udevice *bus) | |
187 | 199 | { |
200 | + struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
188 | 201 | lpi2c_status_t result = LPI2C_SUCESS; |
189 | 202 | u32 status; |
190 | 203 | ulong start_time; |
191 | 204 | |
192 | 205 | |
193 | 206 | |
194 | 207 | |
195 | 208 | |
... | ... | @@ -219,28 +232,28 @@ |
219 | 232 | return result; |
220 | 233 | } |
221 | 234 | |
222 | -static int bus_i2c_read(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len) | |
235 | +static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len) | |
223 | 236 | { |
224 | 237 | lpi2c_status_t result = LPI2C_SUCESS; |
225 | 238 | |
226 | - result = bus_i2c_start(regs, chip, 1); | |
239 | + result = bus_i2c_start(bus, chip, 1); | |
227 | 240 | if (result) |
228 | 241 | return result; |
229 | - result = bus_i2c_receive(regs, buf, len); | |
242 | + result = bus_i2c_receive(bus, buf, len); | |
230 | 243 | if (result) |
231 | 244 | return result; |
232 | 245 | |
233 | 246 | return result; |
234 | 247 | } |
235 | 248 | |
236 | -static int bus_i2c_write(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len) | |
249 | +static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len) | |
237 | 250 | { |
238 | 251 | lpi2c_status_t result = LPI2C_SUCESS; |
239 | 252 | |
240 | - result = bus_i2c_start(regs, chip, 0); | |
253 | + result = bus_i2c_start(bus, chip, 0); | |
241 | 254 | if (result) |
242 | 255 | return result; |
243 | - result = bus_i2c_send(regs, buf, len); | |
256 | + result = bus_i2c_send(bus, buf, len); | |
244 | 257 | if (result) |
245 | 258 | return result; |
246 | 259 | |
247 | 260 | |
248 | 261 | |
249 | 262 | |
... | ... | @@ -355,18 +368,16 @@ |
355 | 368 | static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip, |
356 | 369 | u32 chip_flags) |
357 | 370 | { |
358 | - struct imx_lpi2c_reg *regs; | |
359 | 371 | lpi2c_status_t result = LPI2C_SUCESS; |
360 | 372 | |
361 | - regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
362 | - result = bus_i2c_start(regs, chip, 0); | |
373 | + result = bus_i2c_start(bus, chip, 0); | |
363 | 374 | if (result) { |
364 | - bus_i2c_stop(regs); | |
375 | + bus_i2c_stop(bus); | |
365 | 376 | bus_i2c_init(bus, 100000); |
366 | 377 | return result; |
367 | 378 | } |
368 | 379 | |
369 | - result = bus_i2c_stop(regs); | |
380 | + result = bus_i2c_stop(bus); | |
370 | 381 | if (result) |
371 | 382 | bus_i2c_init(bus, 100000); |
372 | 383 | |
373 | 384 | |
374 | 385 | |
375 | 386 | |
... | ... | @@ -375,16 +386,14 @@ |
375 | 386 | |
376 | 387 | static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) |
377 | 388 | { |
378 | - struct imx_lpi2c_reg *regs; | |
379 | 389 | int ret = 0, ret_stop; |
380 | 390 | |
381 | - regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); | |
382 | 391 | for (; nmsgs > 0; nmsgs--, msg++) { |
383 | 392 | debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len); |
384 | 393 | if (msg->flags & I2C_M_RD) |
385 | - ret = bus_i2c_read(regs, msg->addr, msg->buf, msg->len); | |
394 | + ret = bus_i2c_read(bus, msg->addr, msg->buf, msg->len); | |
386 | 395 | else { |
387 | - ret = bus_i2c_write(regs, msg->addr, msg->buf, | |
396 | + ret = bus_i2c_write(bus, msg->addr, msg->buf, | |
388 | 397 | msg->len); |
389 | 398 | if (ret) |
390 | 399 | break; |
... | ... | @@ -394,7 +403,7 @@ |
394 | 403 | if (ret) |
395 | 404 | debug("i2c_write: error sending\n"); |
396 | 405 | |
397 | - ret_stop = bus_i2c_stop(regs); | |
406 | + ret_stop = bus_i2c_stop(bus); | |
398 | 407 | if (ret_stop) |
399 | 408 | debug("i2c_xfer: stop bus error\n"); |
400 | 409 |