diff mbox

[V5] i2c: imx: implement bus recovery

Message ID 1441968155-10918-1-git-send-email-b54642@freescale.com
State Superseded
Headers show

Commit Message

Gao Pan Sept. 11, 2015, 10:42 a.m. UTC
Implement bus recovery methods for i2c-imx so we can recover from
situations where SCL/SDA are stuck low.

Once i2c bus SCL/SDA are stuck low during transfer, config the i2c
pinctrl to gpio mode by calling pinctrl sleep set function, and then
use GPIO to emulate the i2c protocol to send nine dummy clock to recover
i2c device. After recovery, set i2c pinctrl to default group setting.

Signed-off-by: Fugang Duan <B38611@freescale.com>
Signed-off-by: Gao Pan <b54642@freescale.com>
---
V2:
As Uwe Kleine-König's suggestion, the version do below changes:
 -replace of_get_named_gpio() with devm_gpiod_get_optional()
 -move gpio_direction_input() and gpio_direction_output() call to the
  prepare callback
 -use 0 and 1 as return value for the get_scl and get_sda callbacks

V3:
 -replace "...-gpio" with "...-gpios" in i2c binding doc
 -document the requirement of using sleep state to configure
  the pins as gpio in i2c binding doc
 -remove i2c_recover_bus() in i2c_imx_trx_complete()
 -use GPIOD_OUT_HIGH as the parameter of devm_gpiod_get_optional to
  config the gpios as output high
 -add error disposal as devm_gpiod_get_optional meets error

V4:
 -remove include <linux/of_gpio.h>
 -call i2c_recover_bus under the condition of the existing of
  both sda and scl. Drop the sda and scl check in i2c_imx_get_scl,
  i2c_imx_get_sda, i2c_imx_set_scl, i2c_imx_prepare_recovery and
  i2c_imx_prepare_recovery
 -use GPIOD_OUT_IN as the parameter of devm_gpiod_get_optional
 -remove documenting the requirement of using sleep state to configure
  the pins as gpio in i2c binding doc

V5:
 -introduce a dedicated gpio state for bus recovery.
 -assign adapter.bus_recovery_info after the two gpios were aquired successfully.

 Documentation/devicetree/bindings/i2c/i2c-imx.txt |   9 ++
 drivers/i2c/busses/i2c-imx.c                      | 121 ++++++++++++++++++++--
 2 files changed, 123 insertions(+), 7 deletions(-)

Comments

Gao Pandy Sept. 18, 2015, 7:40 a.m. UTC | #1
UGluZy4uLg0KRnJvbTogR2FvIFBhbiA8bWFpbHRvOmI1NDY0MkBmcmVlc2NhbGUuY29tPiBTZW50
OiBGcmlkYXksIFNlcHRlbWJlciAxMSwgMjAxNSA2OjQzIFBNDQo+IFRvOiB3c2FAdGhlLWRyZWFt
cy5kZTsgdS5rbGVpbmUta29lbmlnQHBlbmd1dHJvbml4LmRlOw0KPiBzaGF3bmd1b0BrZXJuZWwu
b3JnOyBrZXJuZWxAcGVuZ3V0cm9uaXguZGUNCj4gQ2M6IGxpbnV4LWkyY0B2Z2VyLmtlcm5lbC5v
cmc7IExpIEZyYW5rLUIyMDU5NjsgRHVhbiBGdWdhbmctQjM4NjExOyBHYW8NCj4gUGFuLUI1NDY0
MjsgbGludXgtYXJtLWtlcm5lbEBsaXN0cy5pbmZyYWRlYWQub3JnDQo+IFN1YmplY3Q6IFtQYXRj
aCBWNV0gaTJjOiBpbXg6IGltcGxlbWVudCBidXMgcmVjb3ZlcnkNCj4gDQo+IEltcGxlbWVudCBi
dXMgcmVjb3ZlcnkgbWV0aG9kcyBmb3IgaTJjLWlteCBzbyB3ZSBjYW4gcmVjb3ZlciBmcm9tDQo+
IHNpdHVhdGlvbnMgd2hlcmUgU0NML1NEQSBhcmUgc3R1Y2sgbG93Lg0KPiANCj4gT25jZSBpMmMg
YnVzIFNDTC9TREEgYXJlIHN0dWNrIGxvdyBkdXJpbmcgdHJhbnNmZXIsIGNvbmZpZyB0aGUgaTJj
DQo+IHBpbmN0cmwgdG8gZ3BpbyBtb2RlIGJ5IGNhbGxpbmcgcGluY3RybCBzbGVlcCBzZXQgZnVu
Y3Rpb24sIGFuZCB0aGVuIHVzZQ0KPiBHUElPIHRvIGVtdWxhdGUgdGhlIGkyYyBwcm90b2NvbCB0
byBzZW5kIG5pbmUgZHVtbXkgY2xvY2sgdG8gcmVjb3ZlciBpMmMNCj4gZGV2aWNlLiBBZnRlciBy
ZWNvdmVyeSwgc2V0IGkyYyBwaW5jdHJsIHRvIGRlZmF1bHQgZ3JvdXAgc2V0dGluZy4NCj4gDQo+
IFNpZ25lZC1vZmYtYnk6IEZ1Z2FuZyBEdWFuIDxCMzg2MTFAZnJlZXNjYWxlLmNvbT4NCj4gU2ln
bmVkLW9mZi1ieTogR2FvIFBhbiA8YjU0NjQyQGZyZWVzY2FsZS5jb20+DQo+IC0tLQ0KPiBWMjoN
Cj4gQXMgVXdlIEtsZWluZS1Lw7ZuaWcncyBzdWdnZXN0aW9uLCB0aGUgdmVyc2lvbiBkbyBiZWxv
dyBjaGFuZ2VzOg0KPiAgLXJlcGxhY2Ugb2ZfZ2V0X25hbWVkX2dwaW8oKSB3aXRoIGRldm1fZ3Bp
b2RfZ2V0X29wdGlvbmFsKCkgIC1tb3ZlDQo+IGdwaW9fZGlyZWN0aW9uX2lucHV0KCkgYW5kIGdw
aW9fZGlyZWN0aW9uX291dHB1dCgpIGNhbGwgdG8gdGhlDQo+ICAgcHJlcGFyZSBjYWxsYmFjaw0K
PiAgLXVzZSAwIGFuZCAxIGFzIHJldHVybiB2YWx1ZSBmb3IgdGhlIGdldF9zY2wgYW5kIGdldF9z
ZGEgY2FsbGJhY2tzDQo+IA0KPiBWMzoNCj4gIC1yZXBsYWNlICIuLi4tZ3BpbyIgd2l0aCAiLi4u
LWdwaW9zIiBpbiBpMmMgYmluZGluZyBkb2MgIC1kb2N1bWVudCB0aGUNCj4gcmVxdWlyZW1lbnQg
b2YgdXNpbmcgc2xlZXAgc3RhdGUgdG8gY29uZmlndXJlDQo+ICAgdGhlIHBpbnMgYXMgZ3BpbyBp
biBpMmMgYmluZGluZyBkb2MNCj4gIC1yZW1vdmUgaTJjX3JlY292ZXJfYnVzKCkgaW4gaTJjX2lt
eF90cnhfY29tcGxldGUoKSAgLXVzZSBHUElPRF9PVVRfSElHSA0KPiBhcyB0aGUgcGFyYW1ldGVy
IG9mIGRldm1fZ3Bpb2RfZ2V0X29wdGlvbmFsIHRvDQo+ICAgY29uZmlnIHRoZSBncGlvcyBhcyBv
dXRwdXQgaGlnaA0KPiAgLWFkZCBlcnJvciBkaXNwb3NhbCBhcyBkZXZtX2dwaW9kX2dldF9vcHRp
b25hbCBtZWV0cyBlcnJvcg0KPiANCj4gVjQ6DQo+ICAtcmVtb3ZlIGluY2x1ZGUgPGxpbnV4L29m
X2dwaW8uaD4NCj4gIC1jYWxsIGkyY19yZWNvdmVyX2J1cyB1bmRlciB0aGUgY29uZGl0aW9uIG9m
IHRoZSBleGlzdGluZyBvZg0KPiAgIGJvdGggc2RhIGFuZCBzY2wuIERyb3AgdGhlIHNkYSBhbmQg
c2NsIGNoZWNrIGluIGkyY19pbXhfZ2V0X3NjbCwNCj4gICBpMmNfaW14X2dldF9zZGEsIGkyY19p
bXhfc2V0X3NjbCwgaTJjX2lteF9wcmVwYXJlX3JlY292ZXJ5IGFuZA0KPiAgIGkyY19pbXhfcHJl
cGFyZV9yZWNvdmVyeQ0KPiAgLXVzZSBHUElPRF9PVVRfSU4gYXMgdGhlIHBhcmFtZXRlciBvZiBk
ZXZtX2dwaW9kX2dldF9vcHRpb25hbCAgLXJlbW92ZQ0KPiBkb2N1bWVudGluZyB0aGUgcmVxdWly
ZW1lbnQgb2YgdXNpbmcgc2xlZXAgc3RhdGUgdG8gY29uZmlndXJlDQo+ICAgdGhlIHBpbnMgYXMg
Z3BpbyBpbiBpMmMgYmluZGluZyBkb2MNCj4gDQo+IFY1Og0KPiAgLWludHJvZHVjZSBhIGRlZGlj
YXRlZCBncGlvIHN0YXRlIGZvciBidXMgcmVjb3ZlcnkuDQo+ICAtYXNzaWduIGFkYXB0ZXIuYnVz
X3JlY292ZXJ5X2luZm8gYWZ0ZXIgdGhlIHR3byBncGlvcyB3ZXJlIGFxdWlyZWQNCj4gc3VjY2Vz
c2Z1bGx5Lg0KPiANCj4gIERvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9pMmMvaTJj
LWlteC50eHQgfCAgIDkgKysNCj4gIGRyaXZlcnMvaTJjL2J1c3Nlcy9pMmMtaW14LmMgICAgICAg
ICAgICAgICAgICAgICAgfCAxMjENCj4gKysrKysrKysrKysrKysrKysrKystLQ0KPiAgMiBmaWxl
cyBjaGFuZ2VkLCAxMjMgaW5zZXJ0aW9ucygrKSwgNyBkZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYg
LS1naXQgYS9Eb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvaTJjL2kyYy1pbXgudHh0
DQo+IGIvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2kyYy9pMmMtaW14LnR4dA0K
PiBpbmRleCBjZTQzMTFkLi5lYWI1ODM2IDEwMDY0NA0KPiAtLS0gYS9Eb2N1bWVudGF0aW9uL2Rl
dmljZXRyZWUvYmluZGluZ3MvaTJjL2kyYy1pbXgudHh0DQo+ICsrKyBiL0RvY3VtZW50YXRpb24v
ZGV2aWNldHJlZS9iaW5kaW5ncy9pMmMvaTJjLWlteC50eHQNCj4gQEAgLTE0LDYgKzE0LDEwIEBA
IE9wdGlvbmFsIHByb3BlcnRpZXM6DQo+ICAgIFRoZSBhYnNlbmNlIG9mIHRoZSBwcm9wb2VydHkg
aW5kaWNhdGVzIHRoZSBkZWZhdWx0IGZyZXF1ZW5jeSAxMDAga0h6Lg0KPiAgLSBkbWFzOiBBIGxp
c3Qgb2YgdHdvIGRtYSBzcGVjaWZpZXJzLCBvbmUgZm9yIGVhY2ggZW50cnkgaW4gZG1hLW5hbWVz
Lg0KPiAgLSBkbWEtbmFtZXM6IHNob3VsZCBjb250YWluICJ0eCIgYW5kICJyeCIuDQo+ICstIHNj
bC1ncGlvczogc3BlY2lmeSB0aGUgZ3BpbyByZWxhdGVkIHRvIFNDTCBwaW4NCj4gKy0gc2RhLWdw
aW9zOiBzcGVjaWZ5IHRoZSBncGlvIHJlbGF0ZWQgdG8gU0RBIHBpbg0KPiArLSBwaW5jdHJsOiBh
ZGQgZXh0cmEgcGluY3RybCB0byBjb25maWd1cmUgaTJjIHBpbnMgdG8gZ3BpbyBmdW5jdGlvbiBm
b3INCj4gK2kyYw0KPiArICBidXMgcmVjb3ZlcnksIGNhbGwgaXQgImdwaW8iIHN0YXRlDQo+IA0K
PiAgRXhhbXBsZXM6DQo+IA0KPiBAQCAtMzcsNCArNDEsOSBAQCBpMmMwOiBpMmNANDAwNjYwMDAg
eyAvKiBpMmMwIG9uIHZmNjEwICovDQo+ICAJZG1hcyA9IDwmZWRtYTAgMCA1MD4sDQo+ICAJCTwm
ZWRtYTAgMCA1MT47DQo+ICAJZG1hLW5hbWVzID0gInJ4IiwidHgiOw0KPiArCXBpbmN0cmwtbmFt
ZXMgPSAiZGVmYXVsdCIsICJncGlvIjsNCj4gKwlwaW5jdHJsLTAgPSA8JnBpbmN0cmxfaTJjMT47
DQo+ICsJcGluY3RybC0xID0gPCZwaW5jdHJsX2kyYzFfZ3Bpbz47DQo+ICsJc2NsLWdwaW9zID0g
PCZncGlvNSAyNiBHUElPX0FDVElWRV9ISUdIPjsNCj4gKwlzZGEtZ3Bpb3MgPSA8JmdwaW81IDI3
IEdQSU9fQUNUSVZFX0hJR0g+Ow0KPiAgfTsNCj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaTJjL2J1
c3Nlcy9pMmMtaW14LmMgYi9kcml2ZXJzL2kyYy9idXNzZXMvaTJjLWlteC5jDQo+IGluZGV4IGQ3
YzgyM2IuLjkwYzBlMGYgMTAwNjQ0DQo+IC0tLSBhL2RyaXZlcnMvaTJjL2J1c3Nlcy9pMmMtaW14
LmMNCj4gKysrIGIvZHJpdmVycy9pMmMvYnVzc2VzL2kyYy1pbXguYw0KPiBAQCAtNDAsNiArNDAs
NyBAQA0KPiAgI2luY2x1ZGUgPGxpbnV4L2RtYXBvb2wuaD4NCj4gICNpbmNsdWRlIDxsaW51eC9l
cnIuaD4NCj4gICNpbmNsdWRlIDxsaW51eC9lcnJuby5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2dw
aW8uaD4NCj4gICNpbmNsdWRlIDxsaW51eC9pMmMuaD4NCj4gICNpbmNsdWRlIDxsaW51eC9pbml0
Lmg+DQo+ICAjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+DQo+IEBAIC02NCw2ICs2NSw4IEBA
DQo+ICAvKiBEZWZhdWx0IHZhbHVlICovDQo+ICAjZGVmaW5lIElNWF9JMkNfQklUX1JBVEUJMTAw
MDAwCS8qIDEwMGtIeiAqLw0KPiANCj4gKyNkZWZpbmUgSTJDX1BJTkNUUkxfU1RBVEVfR1BJTwki
Z3BpbyINCj4gKw0KPiAgLyoNCj4gICAqIEVuYWJsZSBETUEgaWYgdHJhbnNmZXIgYnl0ZSBzaXpl
IGlzIGJpZ2dlciB0aGFuIHRoaXMgdGhyZXNob2xkLg0KPiAgICogQXMgdGhlIGhhcmR3YXJlIHJl
cXVlc3QsIGl0IG11c3QgYmlnZ2VyIHRoYW4gNCBieXRlcy5cIEBAIC0xNzgsNg0KPiArMTgxLDEx
IEBAIGVudW0gaW14X2kyY190eXBlIHsNCj4gIAlWRjYxMF9JMkMsDQo+ICB9Ow0KPiANCj4gK3N0
cnVjdCBpbXhfaTJjX3BpbmN0cmwgew0KPiArCXN0cnVjdCBncGlvX2Rlc2MgKnNkYTsNCj4gKwlz
dHJ1Y3QgZ3Bpb19kZXNjICpzY2w7DQo+ICt9Ow0KPiArDQo+ICBzdHJ1Y3QgaW14X2kyY19od2Rh
dGEgew0KPiAgCWVudW0gaW14X2kyY190eXBlCWRldnR5cGU7DQo+ICAJdW5zaWduZWQJCXJlZ3No
aWZ0Ow0KPiBAQCAtMjA5LDggKzIxNywxMyBAQCBzdHJ1Y3QgaW14X2kyY19zdHJ1Y3Qgew0KPiAg
CXVuc2lnbmVkIGludAkJaWZkcjsgLyogSU1YX0kyQ19JRkRSICovDQo+ICAJdW5zaWduZWQgaW50
CQljdXJfY2xrOw0KPiAgCXVuc2lnbmVkIGludAkJYml0cmF0ZTsNCj4gKwlzdHJ1Y3QgaW14X2ky
Y19waW5jdHJsCXBpbnM7DQo+ICAJY29uc3Qgc3RydWN0IGlteF9pMmNfaHdkYXRhCSpod2RhdGE7
DQo+IA0KPiArCXN0cnVjdCBwaW5jdHJsICpwaW5jdHJsOw0KPiArCXN0cnVjdCBwaW5jdHJsX3N0
YXRlICpwaW5jdHJsX3BpbnNfZGVmYXVsdDsNCj4gKwlzdHJ1Y3QgcGluY3RybF9zdGF0ZSAqcGlu
Y3RybF9waW5zX2dwaW87DQo+ICsNCj4gIAlzdHJ1Y3QgaW14X2kyY19kbWEJKmRtYTsNCj4gIH07
DQo+IA0KPiBAQCAtNDM5LDcgKzQ1MiwxMCBAQCBzdGF0aWMgaW50IGkyY19pbXhfYnVzX2J1c3ko
c3RydWN0IGlteF9pMmNfc3RydWN0DQo+ICppMmNfaW14LCBpbnQgZm9yX2J1c3kpDQo+ICAJCWlm
ICh0aW1lX2FmdGVyKGppZmZpZXMsIG9yaWdfamlmZmllcyArIG1zZWNzX3RvX2ppZmZpZXMoNTAw
KSkpDQo+IHsNCj4gIAkJCWRldl9kYmcoJmkyY19pbXgtPmFkYXB0ZXIuZGV2LA0KPiAgCQkJCSI8
JXM+IEkyQyBidXMgaXMgYnVzeVxuIiwgX19mdW5jX18pOw0KPiAtCQkJcmV0dXJuIC1FVElNRURP
VVQ7DQo+ICsJCQlpZiAoaTJjX2lteC0+YWRhcHRlci5idXNfcmVjb3ZlcnlfaW5mbykNCj4gKwkJ
CQlyZXR1cm4gaTJjX3JlY292ZXJfYnVzKCZpMmNfaW14LT5hZGFwdGVyKTsNCj4gKwkJCWVsc2UN
Cj4gKwkJCQlyZXR1cm4gLUVUSU1FRE9VVDsNCj4gIAkJfQ0KPiAgCQlzY2hlZHVsZSgpOw0KPiAg
CX0NCj4gQEAgLTk2Myw2ICs5NzksNjIgQEAgb3V0Og0KPiAgCXJldHVybiAocmVzdWx0IDwgMCkg
PyByZXN1bHQgOiBudW07DQo+ICB9DQo+IA0KPiArc3RhdGljIGludCBpMmNfaW14X2dldF9zY2wo
c3RydWN0IGkyY19hZGFwdGVyICphZGFwKSB7DQo+ICsJc3RydWN0IGlteF9pMmNfc3RydWN0ICpp
MmNfaW14Ow0KPiArDQo+ICsJaTJjX2lteCA9IGNvbnRhaW5lcl9vZihhZGFwLCBzdHJ1Y3QgaW14
X2kyY19zdHJ1Y3QsIGFkYXB0ZXIpOw0KPiArDQo+ICsJcmV0dXJuIGdwaW9kX2dldF92YWx1ZShp
MmNfaW14LT5waW5zLnNjbCk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBpbnQgaTJjX2lteF9nZXRf
c2RhKHN0cnVjdCBpMmNfYWRhcHRlciAqYWRhcCkgew0KPiArCXN0cnVjdCBpbXhfaTJjX3N0cnVj
dCAqaTJjX2lteDsNCj4gKw0KPiArCWkyY19pbXggPSBjb250YWluZXJfb2YoYWRhcCwgc3RydWN0
IGlteF9pMmNfc3RydWN0LCBhZGFwdGVyKTsNCj4gKw0KPiArCXJldHVybiBncGlvZF9nZXRfdmFs
dWUoaTJjX2lteC0+cGlucy5zZGEpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBpMmNfaW14
X3NldF9zY2woc3RydWN0IGkyY19hZGFwdGVyICphZGFwLCBpbnQgdmFsKSB7DQo+ICsJc3RydWN0
IGlteF9pMmNfc3RydWN0ICppMmNfaW14Ow0KPiArDQo+ICsJaTJjX2lteCA9IGNvbnRhaW5lcl9v
ZihhZGFwLCBzdHJ1Y3QgaW14X2kyY19zdHJ1Y3QsIGFkYXB0ZXIpOw0KPiArDQo+ICsJZ3Bpb2Rf
c2V0X3ZhbHVlKGkyY19pbXgtPnBpbnMuc2NsLCB2YWwpOyB9DQo+ICsNCj4gK3N0YXRpYyB2b2lk
IGkyY19pbXhfcHJlcGFyZV9yZWNvdmVyeShzdHJ1Y3QgaTJjX2FkYXB0ZXIgKmFkYXApIHsNCj4g
KwlzdHJ1Y3QgaW14X2kyY19zdHJ1Y3QgKmkyY19pbXg7DQo+ICsNCj4gKwlpMmNfaW14ID0gY29u
dGFpbmVyX29mKGFkYXAsIHN0cnVjdCBpbXhfaTJjX3N0cnVjdCwgYWRhcHRlcik7DQo+ICsNCj4g
KwlwaW5jdHJsX3NlbGVjdF9zdGF0ZShpMmNfaW14LT5waW5jdHJsLCBpMmNfaW14LT5waW5jdHJs
X3BpbnNfZ3Bpbyk7DQo+ICsJZ3Bpb2RfZGlyZWN0aW9uX2lucHV0KGkyY19pbXgtPnBpbnMuc2Rh
KTsNCj4gKwlncGlvZF9kaXJlY3Rpb25fb3V0cHV0KGkyY19pbXgtPnBpbnMuc2NsLCAxKTsgfQ0K
PiArDQo+ICtzdGF0aWMgdm9pZCBpMmNfaW14X3VucHJlcGFyZV9yZWNvdmVyeShzdHJ1Y3QgaTJj
X2FkYXB0ZXIgKmFkYXApIHsNCj4gKwlzdHJ1Y3QgaW14X2kyY19zdHJ1Y3QgKmkyY19pbXg7DQo+
ICsNCj4gKwlpMmNfaW14ID0gY29udGFpbmVyX29mKGFkYXAsIHN0cnVjdCBpbXhfaTJjX3N0cnVj
dCwgYWRhcHRlcik7DQo+ICsNCj4gKwlwaW5jdHJsX3NlbGVjdF9zdGF0ZShpMmNfaW14LT5waW5j
dHJsLCBpMmNfaW14LQ0KPiA+cGluY3RybF9waW5zX2RlZmF1bHQpOw0KPiArfQ0KPiArDQo+ICtz
dGF0aWMgc3RydWN0IGkyY19idXNfcmVjb3ZlcnlfaW5mbyBpMmNfaW14X2J1c19yZWNvdmVyeV9p
bmZvID0gew0KPiArCS5nZXRfc2NsID0gaTJjX2lteF9nZXRfc2NsLA0KPiArCS5nZXRfc2RhID0g
aTJjX2lteF9nZXRfc2RhLA0KPiArCS5zZXRfc2NsID0gaTJjX2lteF9zZXRfc2NsLA0KPiArCS5w
cmVwYXJlX3JlY292ZXJ5ID0gaTJjX2lteF9wcmVwYXJlX3JlY292ZXJ5LA0KPiArCS51bnByZXBh
cmVfcmVjb3ZlcnkgPSBpMmNfaW14X3VucHJlcGFyZV9yZWNvdmVyeSwNCj4gKwkucmVjb3Zlcl9i
dXMgPSBpMmNfZ2VuZXJpY19zY2xfcmVjb3ZlcnksIH07DQo+ICsNCj4gIHN0YXRpYyB1MzIgaTJj
X2lteF9mdW5jKHN0cnVjdCBpMmNfYWRhcHRlciAqYWRhcHRlcikgIHsNCj4gIAlyZXR1cm4gSTJD
X0ZVTkNfSTJDIHwgSTJDX0ZVTkNfU01CVVNfRU1VTCBAQCAtMTAxMSwxMiArMTA4MywxMiBAQA0K
PiBzdGF0aWMgaW50IGkyY19pbXhfcHJvYmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikN
Cj4gDQo+ICAJLyogU2V0dXAgaTJjX2lteCBkcml2ZXIgc3RydWN0dXJlICovDQo+ICAJc3RybGNw
eShpMmNfaW14LT5hZGFwdGVyLm5hbWUsIHBkZXYtPm5hbWUsIHNpemVvZihpMmNfaW14LQ0KPiA+
YWRhcHRlci5uYW1lKSk7DQo+IC0JaTJjX2lteC0+YWRhcHRlci5vd25lcgkJPSBUSElTX01PRFVM
RTsNCj4gLQlpMmNfaW14LT5hZGFwdGVyLmFsZ28JCT0gJmkyY19pbXhfYWxnbzsNCj4gLQlpMmNf
aW14LT5hZGFwdGVyLmRldi5wYXJlbnQJPSAmcGRldi0+ZGV2Ow0KPiAtCWkyY19pbXgtPmFkYXB0
ZXIubnIJCT0gcGRldi0+aWQ7DQo+IC0JaTJjX2lteC0+YWRhcHRlci5kZXYub2Zfbm9kZQk9IHBk
ZXYtPmRldi5vZl9ub2RlOw0KPiAtCWkyY19pbXgtPmJhc2UJCQk9IGJhc2U7DQo+ICsJaTJjX2lt
eC0+YWRhcHRlci5vd25lciA9IFRISVNfTU9EVUxFOw0KPiArCWkyY19pbXgtPmFkYXB0ZXIuYWxn
byA9ICZpMmNfaW14X2FsZ287DQo+ICsJaTJjX2lteC0+YWRhcHRlci5kZXYucGFyZW50ID0gJnBk
ZXYtPmRldjsNCj4gKwlpMmNfaW14LT5hZGFwdGVyLm5yID0gcGRldi0+aWQ7DQo+ICsJaTJjX2lt
eC0+YWRhcHRlci5kZXYub2Zfbm9kZSA9IHBkZXYtPmRldi5vZl9ub2RlOw0KPiArCWkyY19pbXgt
PmJhc2UgPSBiYXNlOw0KPiANCj4gIAkvKiBHZXQgSTJDIGNsb2NrICovDQo+ICAJaTJjX2lteC0+
Y2xrID0gZGV2bV9jbGtfZ2V0KCZwZGV2LT5kZXYsIE5VTEwpOyBAQCAtMTAzMSw2ICsxMTAzLDIz
DQo+IEBAIHN0YXRpYyBpbnQgaTJjX2lteF9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpw
ZGV2KQ0KPiAgCQlyZXR1cm4gcmV0Ow0KPiAgCX0NCj4gDQo+ICsJaTJjX2lteC0+cGluY3RybCA9
IGRldm1fcGluY3RybF9nZXQoJnBkZXYtPmRldik7DQo+ICsJaWYgKElTX0VSUihpMmNfaW14LT5w
aW5jdHJsKSkgew0KPiArCQlyZXQgPSBQVFJfRVJSKGkyY19pbXgtPnBpbmN0cmwpOw0KPiArCQln
b3RvIGNsa19kaXNhYmxlOw0KPiArCX0NCj4gKw0KPiArCWkyY19pbXgtPnBpbmN0cmxfcGluc19k
ZWZhdWx0ID0gcGluY3RybF9sb29rdXBfc3RhdGUoaTJjX2lteC0NCj4gPnBpbmN0cmwsDQo+ICsJ
CQkJCQlQSU5DVFJMX1NUQVRFX0RFRkFVTFQpOw0KPiArCWlmIChJU19FUlIoaTJjX2lteC0+cGlu
Y3RybF9waW5zX2RlZmF1bHQpKQ0KPiArCQlkZXZfd2FybigmcGRldi0+ZGV2LCAiY291bGQgbm90
IGdldCBkZWZhdWx0IHN0YXRlXG4iKTsNCj4gKwllbHNlIHsNCj4gKwkJaTJjX2lteC0+cGluY3Ry
bF9waW5zX2dwaW8gPSBwaW5jdHJsX2xvb2t1cF9zdGF0ZShpMmNfaW14LQ0KPiA+cGluY3RybCwN
Cj4gKwkJCQkJCUkyQ19QSU5DVFJMX1NUQVRFX0dQSU8pOw0KPiArCQlpZiAoSVNfRVJSKGkyY19p
bXgtPnBpbmN0cmxfcGluc19ncGlvKSkNCj4gKwkJCWRldl93YXJuKCZwZGV2LT5kZXYsICJjb3Vs
ZCBub3QgZ2V0IGdwaW8gc3RhdGVcbiIpOw0KPiArCX0NCj4gKw0KPiAgCS8qIFJlcXVlc3QgSVJR
ICovDQo+ICAJcmV0ID0gZGV2bV9yZXF1ZXN0X2lycSgmcGRldi0+ZGV2LCBpcnEsIGkyY19pbXhf
aXNyLCAwLA0KPiAgCQkJCXBkZXYtPm5hbWUsIGkyY19pbXgpOw0KPiBAQCAtMTA1Nyw2ICsxMTQ2
LDI0IEBAIHN0YXRpYyBpbnQgaTJjX2lteF9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlDQo+
ICpwZGV2KQ0KPiAgCWlmIChyZXQgPCAwKQ0KPiAgCQlnb3RvIHJwbV9kaXNhYmxlOw0KPiANCj4g
KwkvKiBJbml0IHJlY292ZXIgcGlucyAqLw0KPiArCWkyY19pbXgtPnBpbnMuc2RhID0NCj4gKwkJ
ZGV2bV9ncGlvZF9nZXRfb3B0aW9uYWwoJnBkZXYtPmRldiwgInNkYS1ncGlvcyIsIEdQSU9EX0lO
KTsNCj4gKwlpMmNfaW14LT5waW5zLnNjbCA9DQo+ICsJCWRldm1fZ3Bpb2RfZ2V0X29wdGlvbmFs
KCZwZGV2LT5kZXYsICJzY2wtZ3Bpb3MiLCBHUElPRF9JTik7DQo+ICsNCj4gKwlpZiAoSVNfRVJS
KGkyY19pbXgtPnBpbnMuc2RhKSkgew0KPiArCQlyZXQgPSBQVFJfRVJSKGkyY19pbXgtPnBpbnMu
c2RhKTsNCj4gKwkJZ290byBjbGtfZGlzYWJsZTsNCj4gKwl9DQo+ICsNCj4gKwlpZiAoSVNfRVJS
KGkyY19pbXgtPnBpbnMuc2NsKSkgew0KPiArCQlyZXQgPSBQVFJfRVJSKGkyY19pbXgtPnBpbnMu
c2NsKTsNCj4gKwkJZ290byBjbGtfZGlzYWJsZTsNCj4gKwl9DQo+ICsNCj4gKwlpMmNfaW14LT5h
ZGFwdGVyLmJ1c19yZWNvdmVyeV9pbmZvID0gJmkyY19pbXhfYnVzX3JlY292ZXJ5X2luZm87DQo+
ICsNCj4gIAkvKiBTZXQgdXAgY2xvY2sgZGl2aWRlciAqLw0KPiAgCWkyY19pbXgtPmJpdHJhdGUg
PSBJTVhfSTJDX0JJVF9SQVRFOw0KPiAgCXJldCA9IG9mX3Byb3BlcnR5X3JlYWRfdTMyKHBkZXYt
PmRldi5vZl9ub2RlLA0KPiAtLQ0KPiAxLjkuMQ0K
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König Sept. 18, 2015, 7:54 a.m. UTC | #2
Hello,

On Fri, Sep 11, 2015 at 06:42:34PM +0800, Gao Pan wrote:
> V5:
>  -introduce a dedicated gpio state for bus recovery.
>  -assign adapter.bus_recovery_info after the two gpios were aquired successfully.

You also do this if the gpios were not acquired successfully.

> +	if (IS_ERR(i2c_imx->pinctrl_pins_default))
> +		dev_warn(&pdev->dev, "could not get default state\n");
> +	else {
> +		i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
> +						I2C_PINCTRL_STATE_GPIO);
> +		if (IS_ERR(i2c_imx->pinctrl_pins_gpio))
> +			dev_warn(&pdev->dev, "could not get gpio state\n");

IMHO pinctrl_lookup_state returning an error is enough to not try a
recovery.

> +	}
> +
>  	/* Request IRQ */
>  	ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
>  				pdev->name, i2c_imx);
> @@ -1057,6 +1146,24 @@ static int i2c_imx_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		goto rpm_disable;
>  
> +	/* Init recover pins */
> +	i2c_imx->pins.sda =
> +		devm_gpiod_get_optional(&pdev->dev, "sda-gpios", GPIOD_IN);
> +	i2c_imx->pins.scl =
> +		devm_gpiod_get_optional(&pdev->dev, "scl-gpios", GPIOD_IN);
> +
> +	if (IS_ERR(i2c_imx->pins.sda)) {
> +		ret = PTR_ERR(i2c_imx->pins.sda);
> +		goto clk_disable;
> +	}
> +
> +	if (IS_ERR(i2c_imx->pins.scl)) {
> +		ret = PTR_ERR(i2c_imx->pins.scl);
> +		goto clk_disable;
> +	}
> +

if (i2c_imx->pins.sda && i2c_imx->pins.scl)

> +	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
> +
>  	/* Set up clock divider */
>  	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
>  	ret = of_property_read_u32(pdev->dev.of_node,

Best regards
Uwe
Gao Pandy Sept. 21, 2015, 4:29 a.m. UTC | #3
From: linux-i2c-owner@vger.kernel.org <mailto:linux-i2c-owner@vger.kernel.org> Sent: Friday, September 18, 2015 3:55 PM
> To: Gao Pan-B54642
> Cc: wsa@the-dreams.de; shawnguo@kernel.org; kernel@pengutronix.de; linux-
> i2c@vger.kernel.org; Li Frank-B20596; Duan Fugang-B38611; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [Patch V5] i2c: imx: implement bus recovery
> 
> Hello,
> 
> On Fri, Sep 11, 2015 at 06:42:34PM +0800, Gao Pan wrote:
> > V5:
> >  -introduce a dedicated gpio state for bus recovery.
> >  -assign adapter.bus_recovery_info after the two gpios were aquired
> successfully.
> 
> You also do this if the gpios were not acquired successfully.
 
Thanks. If the gpios are not acquired successfully, the context goes to label clk_disable. So the assignment is skipped.
Please see the following code.

      ......
  
	if (IS_ERR(i2c_imx->pins.sda)) {
		ret = PTR_ERR(i2c_imx->pins.sda);
		goto clk_disable;
	}
	if (IS_ERR(i2c_imx->pins.scl)) {
		ret = PTR_ERR(i2c_imx->pins.scl);
		goto clk_disable;
	}
	
	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;

	......


> 
> > +	if (IS_ERR(i2c_imx->pinctrl_pins_default))
> > +		dev_warn(&pdev->dev, "could not get default state\n");
> > +	else {
> > +		i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx-
> >pinctrl,
> > +						I2C_PINCTRL_STATE_GPIO);
> > +		if (IS_ERR(i2c_imx->pinctrl_pins_gpio))
> > +			dev_warn(&pdev->dev, "could not get gpio state\n");
> 
> IMHO pinctrl_lookup_state returning an error is enough to not try a
> recovery.
 
Thanks, you are right. How about the following logic.

	if (!(IS_ERR(i2c_imx->pinctrl_pins_default)) && !(IS_ERR(i2c_imx->pinctrl_pins_gpio))) {
                i2c_imx->pins.sda =
                        devm_gpiod_get_optional(&pdev->dev, "sda-gpios", GPIOD_IN);
                i2c_imx->pins.scl =
                        devm_gpiod_get_optional(&pdev->dev, "scl-gpios", GPIOD_IN);

                if (IS_ERR(i2c_imx->pins.sda)) {
                        ret = PTR_ERR(i2c_imx->pins.sda);
                        goto clk_disable;
                }

                if (IS_ERR(i2c_imx->pins.scl)) {
                        ret = PTR_ERR(i2c_imx->pins.scl);
                        goto clk_disable;
                }

                i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
	} 


> 
> > +	}
> > +
> >  	/* Request IRQ */
> >  	ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
> >  				pdev->name, i2c_imx);
> > @@ -1057,6 +1146,24 @@ static int i2c_imx_probe(struct platform_device
> *pdev)
> >  	if (ret < 0)
> >  		goto rpm_disable;
> >
> > +	/* Init recover pins */
> > +	i2c_imx->pins.sda =
> > +		devm_gpiod_get_optional(&pdev->dev, "sda-gpios", GPIOD_IN);
> > +	i2c_imx->pins.scl =
> > +		devm_gpiod_get_optional(&pdev->dev, "scl-gpios", GPIOD_IN);
> > +
> > +	if (IS_ERR(i2c_imx->pins.sda)) {
> > +		ret = PTR_ERR(i2c_imx->pins.sda);
> > +		goto clk_disable;
> > +	}
> > +
> > +	if (IS_ERR(i2c_imx->pins.scl)) {
> > +		ret = PTR_ERR(i2c_imx->pins.scl);
> > +		goto clk_disable;
> > +	}
> > +
> 
> if (i2c_imx->pins.sda && i2c_imx->pins.scl)
> 
> > +	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
> > +
> >  	/* Set up clock divider */
> >  	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
> >  	ret = of_property_read_u32(pdev->dev.of_node,
> 
> Best regards
> Uwe
> 
> --
> Pengutronix e.K.                           | Uwe Kleine-König
> |
> Industrial Linux Solutions                 | http://www.pengutronix.de/
> |
> --
> To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
> the body of a message to majordomo@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Uwe Kleine-König Sept. 21, 2015, 6:33 a.m. UTC | #4
Hello,

On Mon, Sep 21, 2015 at 04:29:20AM +0000, Gao Pandy wrote:
> > On Fri, Sep 11, 2015 at 06:42:34PM +0800, Gao Pan wrote:
> > > V5:
> > >  -introduce a dedicated gpio state for bus recovery.
> > >  -assign adapter.bus_recovery_info after the two gpios were aquired
> > >   successfully.
> > 
> > You also do this if the gpios were not acquired successfully.
>  
> Thanks. If the gpios are not acquired successfully, the context goes
> to label clk_disable. So the assignment is skipped.
> Please see the following code.
> 
>       ......
>   
> 	if (IS_ERR(i2c_imx->pins.sda)) {
> 		ret = PTR_ERR(i2c_imx->pins.sda);
> 		goto clk_disable;
> 	}
> 	if (IS_ERR(i2c_imx->pins.scl)) {
> 		ret = PTR_ERR(i2c_imx->pins.scl);
> 		goto clk_disable;
> 	}
> 	
> 	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
> 
> 	......

Right, if devm_gpiod_get_optional returns an error probing fails and
everything is right. If however devm_gpiod_get_optional returns NULL
(i.e. the dt doesn't contain an scl-gpios property) you happily use them
even though gpio_set_value are stubs in this case.
 
> > IMHO pinctrl_lookup_state returning an error is enough to not try a
> > recovery.
>  
> Thanks, you are right. How about the following logic.
> 
> 	if (!(IS_ERR(i2c_imx->pinctrl_pins_default)) && !(IS_ERR(i2c_imx->pinctrl_pins_gpio))) {

After the ! you don't need a (, but apart from this the logic is fine.

>                 i2c_imx->pins.sda =
>                         devm_gpiod_get_optional(&pdev->dev, "sda-gpios", GPIOD_IN);
>                 i2c_imx->pins.scl =
>                         devm_gpiod_get_optional(&pdev->dev, "scl-gpios", GPIOD_IN);
> 
>                 if (IS_ERR(i2c_imx->pins.sda)) {
>                         ret = PTR_ERR(i2c_imx->pins.sda);
>                         goto clk_disable;
>                 }
> 
>                 if (IS_ERR(i2c_imx->pins.scl)) {
>                         ret = PTR_ERR(i2c_imx->pins.scl);
>                         goto clk_disable;
>                 }

As said above, here you need an

		if (i2c_imx->pins.scl && i2c_imx->pins.sda)
>                 i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
> 	} 

Best regards
Uwe
Gao Pandy Sept. 21, 2015, 8:13 a.m. UTC | #5
From: Uwe Kleine-König <mailto:u.kleine-koenig@pengutronix.de> Sent: Monday, September 21, 2015 2:33 PM
> To: Gao Pan-B54642
> Cc: Li Frank-B20596; wsa@the-dreams.de; linux-i2c@vger.kernel.org;
> kernel@pengutronix.de; Duan Fugang-B38611; shawnguo@kernel.org; linux-
> arm-kernel@lists.infradead.org
> Subject: Re: [Patch V5] i2c: imx: implement bus recovery
> 
> Hello,
> 
> On Mon, Sep 21, 2015 at 04:29:20AM +0000, Gao Pandy wrote:
> > > On Fri, Sep 11, 2015 at 06:42:34PM +0800, Gao Pan wrote:
> > > > V5:
> > > >  -introduce a dedicated gpio state for bus recovery.
> > > >  -assign adapter.bus_recovery_info after the two gpios were aquired
> > > >   successfully.
> > >
> > > You also do this if the gpios were not acquired successfully.
> >
> > Thanks. If the gpios are not acquired successfully, the context goes
> > to label clk_disable. So the assignment is skipped.
> > Please see the following code.
> >
> >       ......
> >
> > 	if (IS_ERR(i2c_imx->pins.sda)) {
> > 		ret = PTR_ERR(i2c_imx->pins.sda);
> > 		goto clk_disable;
> > 	}
> > 	if (IS_ERR(i2c_imx->pins.scl)) {
> > 		ret = PTR_ERR(i2c_imx->pins.scl);
> > 		goto clk_disable;
> > 	}
> >
> > 	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
> >
> > 	......
> 
> Right, if devm_gpiod_get_optional returns an error probing fails and
> everything is right. If however devm_gpiod_get_optional returns NULL (i.e.
> the dt doesn't contain an scl-gpios property) you happily use them even
> though gpio_set_value are stubs in this case.
 
Thanks, you are right.

> > > IMHO pinctrl_lookup_state returning an error is enough to not try a
> > > recovery.
> >
> > Thanks, you are right. How about the following logic.
> >
> > 	if (!(IS_ERR(i2c_imx->pinctrl_pins_default)) &&
> > !(IS_ERR(i2c_imx->pinctrl_pins_gpio))) {
> 
> After the ! you don't need a (, but apart from this the logic is fine.
> 
> >                 i2c_imx->pins.sda =
> >                         devm_gpiod_get_optional(&pdev->dev, "sda-gpios",
> GPIOD_IN);
> >                 i2c_imx->pins.scl =
> >                         devm_gpiod_get_optional(&pdev->dev,
> > "scl-gpios", GPIOD_IN);
> >
> >                 if (IS_ERR(i2c_imx->pins.sda)) {
> >                         ret = PTR_ERR(i2c_imx->pins.sda);
> >                         goto clk_disable;
> >                 }
> >
> >                 if (IS_ERR(i2c_imx->pins.scl)) {
> >                         ret = PTR_ERR(i2c_imx->pins.scl);
> >                         goto clk_disable;
> >                 }
> 
> As said above, here you need an
> 
> 		if (i2c_imx->pins.scl && i2c_imx->pins.sda)
> >                 i2c_imx->adapter.bus_recovery_info =
> &i2c_imx_bus_recovery_info;
> > 	}
 
Thank you very much, will fix it in next version.

> Best regards
> Uwe
> 
> --
> Pengutronix e.K.                           | Uwe Kleine-König
> |
> Industrial Linux Solutions                 | http://www.pengutronix.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/i2c/i2c-imx.txt b/Documentation/devicetree/bindings/i2c/i2c-imx.txt
index ce4311d..eab5836 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-imx.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-imx.txt
@@ -14,6 +14,10 @@  Optional properties:
   The absence of the propoerty indicates the default frequency 100 kHz.
 - dmas: A list of two dma specifiers, one for each entry in dma-names.
 - dma-names: should contain "tx" and "rx".
+- scl-gpios: specify the gpio related to SCL pin
+- sda-gpios: specify the gpio related to SDA pin
+- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c
+  bus recovery, call it "gpio" state
 
 Examples:
 
@@ -37,4 +41,9 @@  i2c0: i2c@40066000 { /* i2c0 on vf610 */
 	dmas = <&edma0 0 50>,
 		<&edma0 0 51>;
 	dma-names = "rx","tx";
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+	scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>;
+	sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
 };
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d7c823b..90c0e0f 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -40,6 +40,7 @@ 
 #include <linux/dmapool.h>
 #include <linux/err.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -64,6 +65,8 @@ 
 /* Default value */
 #define IMX_I2C_BIT_RATE	100000	/* 100kHz */
 
+#define I2C_PINCTRL_STATE_GPIO	"gpio"
+
 /*
  * Enable DMA if transfer byte size is bigger than this threshold.
  * As the hardware request, it must bigger than 4 bytes.\
@@ -178,6 +181,11 @@  enum imx_i2c_type {
 	VF610_I2C,
 };
 
+struct imx_i2c_pinctrl {
+	struct gpio_desc *sda;
+	struct gpio_desc *scl;
+};
+
 struct imx_i2c_hwdata {
 	enum imx_i2c_type	devtype;
 	unsigned		regshift;
@@ -209,8 +217,13 @@  struct imx_i2c_struct {
 	unsigned int		ifdr; /* IMX_I2C_IFDR */
 	unsigned int		cur_clk;
 	unsigned int		bitrate;
+	struct imx_i2c_pinctrl	pins;
 	const struct imx_i2c_hwdata	*hwdata;
 
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pinctrl_pins_default;
+	struct pinctrl_state *pinctrl_pins_gpio;
+
 	struct imx_i2c_dma	*dma;
 };
 
@@ -439,7 +452,10 @@  static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
 		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
 			dev_dbg(&i2c_imx->adapter.dev,
 				"<%s> I2C bus is busy\n", __func__);
-			return -ETIMEDOUT;
+			if (i2c_imx->adapter.bus_recovery_info)
+				return i2c_recover_bus(&i2c_imx->adapter);
+			else
+				return -ETIMEDOUT;
 		}
 		schedule();
 	}
@@ -963,6 +979,62 @@  out:
 	return (result < 0) ? result : num;
 }
 
+static int i2c_imx_get_scl(struct i2c_adapter *adap)
+{
+	struct imx_i2c_struct *i2c_imx;
+
+	i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+	return gpiod_get_value(i2c_imx->pins.scl);
+}
+
+static int i2c_imx_get_sda(struct i2c_adapter *adap)
+{
+	struct imx_i2c_struct *i2c_imx;
+
+	i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+	return gpiod_get_value(i2c_imx->pins.sda);
+}
+
+static void i2c_imx_set_scl(struct i2c_adapter *adap, int val)
+{
+	struct imx_i2c_struct *i2c_imx;
+
+	i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+	gpiod_set_value(i2c_imx->pins.scl, val);
+}
+
+static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
+{
+	struct imx_i2c_struct *i2c_imx;
+
+	i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+	pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
+	gpiod_direction_input(i2c_imx->pins.sda);
+	gpiod_direction_output(i2c_imx->pins.scl, 1);
+}
+
+static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
+{
+	struct imx_i2c_struct *i2c_imx;
+
+	i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+	pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
+}
+
+static struct i2c_bus_recovery_info i2c_imx_bus_recovery_info = {
+	.get_scl = i2c_imx_get_scl,
+	.get_sda = i2c_imx_get_sda,
+	.set_scl = i2c_imx_set_scl,
+	.prepare_recovery = i2c_imx_prepare_recovery,
+	.unprepare_recovery = i2c_imx_unprepare_recovery,
+	.recover_bus = i2c_generic_scl_recovery,
+};
+
 static u32 i2c_imx_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -1011,12 +1083,12 @@  static int i2c_imx_probe(struct platform_device *pdev)
 
 	/* Setup i2c_imx driver structure */
 	strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
-	i2c_imx->adapter.owner		= THIS_MODULE;
-	i2c_imx->adapter.algo		= &i2c_imx_algo;
-	i2c_imx->adapter.dev.parent	= &pdev->dev;
-	i2c_imx->adapter.nr		= pdev->id;
-	i2c_imx->adapter.dev.of_node	= pdev->dev.of_node;
-	i2c_imx->base			= base;
+	i2c_imx->adapter.owner = THIS_MODULE;
+	i2c_imx->adapter.algo = &i2c_imx_algo;
+	i2c_imx->adapter.dev.parent = &pdev->dev;
+	i2c_imx->adapter.nr = pdev->id;
+	i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
+	i2c_imx->base = base;
 
 	/* Get I2C clock */
 	i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
@@ -1031,6 +1103,23 @@  static int i2c_imx_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
+	if (IS_ERR(i2c_imx->pinctrl)) {
+		ret = PTR_ERR(i2c_imx->pinctrl);
+		goto clk_disable;
+	}
+
+	i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
+						PINCTRL_STATE_DEFAULT);
+	if (IS_ERR(i2c_imx->pinctrl_pins_default))
+		dev_warn(&pdev->dev, "could not get default state\n");
+	else {
+		i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
+						I2C_PINCTRL_STATE_GPIO);
+		if (IS_ERR(i2c_imx->pinctrl_pins_gpio))
+			dev_warn(&pdev->dev, "could not get gpio state\n");
+	}
+
 	/* Request IRQ */
 	ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
 				pdev->name, i2c_imx);
@@ -1057,6 +1146,24 @@  static int i2c_imx_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto rpm_disable;
 
+	/* Init recover pins */
+	i2c_imx->pins.sda =
+		devm_gpiod_get_optional(&pdev->dev, "sda-gpios", GPIOD_IN);
+	i2c_imx->pins.scl =
+		devm_gpiod_get_optional(&pdev->dev, "scl-gpios", GPIOD_IN);
+
+	if (IS_ERR(i2c_imx->pins.sda)) {
+		ret = PTR_ERR(i2c_imx->pins.sda);
+		goto clk_disable;
+	}
+
+	if (IS_ERR(i2c_imx->pins.scl)) {
+		ret = PTR_ERR(i2c_imx->pins.scl);
+		goto clk_disable;
+	}
+
+	i2c_imx->adapter.bus_recovery_info = &i2c_imx_bus_recovery_info;
+
 	/* Set up clock divider */
 	i2c_imx->bitrate = IMX_I2C_BIT_RATE;
 	ret = of_property_read_u32(pdev->dev.of_node,