Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: imx: implement bus recovery

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>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Gao Pan and committed by
Wolfram Sang
1c4b6c3b 3861841d

+80
+9
Documentation/devicetree/bindings/i2c/i2c-imx.txt
··· 14 14 The absence of the propoerty indicates the default frequency 100 kHz. 15 15 - dmas: A list of two dma specifiers, one for each entry in dma-names. 16 16 - dma-names: should contain "tx" and "rx". 17 + - scl-gpios: specify the gpio related to SCL pin 18 + - sda-gpios: specify the gpio related to SDA pin 19 + - pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c 20 + bus recovery, call it "gpio" state 17 21 18 22 Examples: 19 23 ··· 41 37 dmas = <&edma0 0 50>, 42 38 <&edma0 0 51>; 43 39 dma-names = "rx","tx"; 40 + pinctrl-names = "default", "gpio"; 41 + pinctrl-0 = <&pinctrl_i2c1>; 42 + pinctrl-1 = <&pinctrl_i2c1_gpio>; 43 + scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; 44 + sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; 44 45 };
+71
drivers/i2c/busses/i2c-imx.c
··· 49 49 #include <linux/of.h> 50 50 #include <linux/of_device.h> 51 51 #include <linux/of_dma.h> 52 + #include <linux/of_gpio.h> 52 53 #include <linux/platform_data/i2c-imx.h> 53 54 #include <linux/platform_device.h> 54 55 #include <linux/sched.h> ··· 208 207 unsigned int cur_clk; 209 208 unsigned int bitrate; 210 209 const struct imx_i2c_hwdata *hwdata; 210 + struct i2c_bus_recovery_info rinfo; 211 + 212 + struct pinctrl *pinctrl; 213 + struct pinctrl_state *pinctrl_pins_default; 214 + struct pinctrl_state *pinctrl_pins_gpio; 211 215 212 216 struct imx_i2c_dma *dma; 213 217 }; ··· 902 896 903 897 /* Start I2C transfer */ 904 898 result = i2c_imx_start(i2c_imx); 899 + if (result) { 900 + if (i2c_imx->adapter.bus_recovery_info) { 901 + i2c_recover_bus(&i2c_imx->adapter); 902 + result = i2c_imx_start(i2c_imx); 903 + } 904 + } 905 + 905 906 if (result) 906 907 goto fail0; 907 908 ··· 967 954 (result < 0) ? "error" : "success msg", 968 955 (result < 0) ? result : num); 969 956 return (result < 0) ? result : num; 957 + } 958 + 959 + static void i2c_imx_prepare_recovery(struct i2c_adapter *adap) 960 + { 961 + struct imx_i2c_struct *i2c_imx; 962 + 963 + i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); 964 + 965 + pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio); 966 + } 967 + 968 + static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) 969 + { 970 + struct imx_i2c_struct *i2c_imx; 971 + 972 + i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); 973 + 974 + pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); 975 + } 976 + 977 + static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, 978 + struct platform_device *pdev) 979 + { 980 + struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo; 981 + 982 + i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl, 983 + PINCTRL_STATE_DEFAULT); 984 + i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, 985 + "gpio"); 986 + rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node, 987 + "sda-gpios", 0, NULL); 988 + rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node, 989 + "scl-gpios", 0, NULL); 990 + 991 + if (!gpio_is_valid(rinfo->sda_gpio) || 992 + !gpio_is_valid(rinfo->scl_gpio) || 993 + IS_ERR(i2c_imx->pinctrl_pins_default) || 994 + IS_ERR(i2c_imx->pinctrl_pins_gpio)) { 995 + dev_dbg(&pdev->dev, "recovery information incomplete\n"); 996 + return; 997 + } 998 + 999 + dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", 1000 + rinfo->sda_gpio, rinfo->scl_gpio); 1001 + 1002 + rinfo->prepare_recovery = i2c_imx_prepare_recovery; 1003 + rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; 1004 + rinfo->recover_bus = i2c_generic_gpio_recovery; 1005 + i2c_imx->adapter.bus_recovery_info = rinfo; 970 1006 } 971 1007 972 1008 static u32 i2c_imx_func(struct i2c_adapter *adapter) ··· 1085 1023 dev_err(&pdev->dev, "can't enable I2C clock\n"); 1086 1024 return ret; 1087 1025 } 1026 + 1027 + i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); 1028 + if (IS_ERR(i2c_imx->pinctrl)) { 1029 + ret = PTR_ERR(i2c_imx->pinctrl); 1030 + goto clk_disable; 1031 + } 1032 + 1088 1033 /* Request IRQ */ 1089 1034 ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, 1090 1035 pdev->name, i2c_imx); ··· 1124 1055 dev_err(&pdev->dev, "registration failed\n"); 1125 1056 goto clk_disable; 1126 1057 } 1058 + 1059 + i2c_imx_init_recovery_info(i2c_imx, pdev); 1127 1060 1128 1061 /* Set up platform driver data */ 1129 1062 platform_set_drvdata(pdev, i2c_imx);