Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / arch / arm / mach-tegra / i2c_error_recovery.c
1 /*\r
2  * arch/arm/mach-tegra/i2c_error_recovery.c\r
3  *\r
4  * Copyright (c) 2011, NVIDIA Corporation.\r
5  *\r
6  * This program is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * This program is distributed in the hope that it will be useful, but WITHOUT\r
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for\r
14  * more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License along\r
17  * with this program; if not, write to the Free Software Foundation, Inc.,\r
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19  */\r
20 #include <linux/gpio.h>\r
21 #include <linux/delay.h>\r
22 #include <linux/init.h>\r
23 \r
24 #include <mach/gpio-tegra.h>\r
25 \r
26 #include "board.h"\r
27 \r
28 #define RETRY_MAX_COUNT (9*8+1) /*I2C controller supports eight-byte burst transfer*/\r
29 \r
30 int arb_lost_recovery(int scl_gpio, int sda_gpio)\r
31 {\r
32         int ret;\r
33         int retry = RETRY_MAX_COUNT;\r
34         int recovered_successfully = 0;\r
35         int val;\r
36 \r
37         if ((!scl_gpio) || (!sda_gpio)) {\r
38                 pr_err("not proper input:scl_gpio 0x%08x,"\r
39                         "sda_gpio 0x%08x\n", scl_gpio, sda_gpio);\r
40                 return -EINVAL;;\r
41         }\r
42 \r
43         ret = gpio_request(scl_gpio, "scl_gpio");\r
44         if (ret < 0) {\r
45                 pr_err("error in gpio 0x%08x request 0x%08x\n",\r
46                         scl_gpio, ret);\r
47                 return -EINVAL;;\r
48         }\r
49 \r
50         ret = gpio_request(sda_gpio, "sda_gpio");\r
51         if (ret < 0) {\r
52                 pr_err("error in gpio 0x%08x request 0x%08x\n",\r
53                         sda_gpio, ret);\r
54                 goto err;\r
55         }\r
56         gpio_direction_input(sda_gpio);\r
57 \r
58         while (retry--) {\r
59                 gpio_direction_output(scl_gpio,0);\r
60                 udelay(5);\r
61                 gpio_direction_output(scl_gpio,1);\r
62                 udelay(5);\r
63 \r
64                 /* check whether sda struct low release */\r
65                 val = gpio_get_value(sda_gpio);\r
66                 if (val) {\r
67                         /* send START */\r
68                         gpio_direction_output(sda_gpio,0);\r
69                         udelay(5);\r
70 \r
71                         /* send STOP in next clock cycle */\r
72                         gpio_direction_output(scl_gpio,0);\r
73                         udelay(5);\r
74                         gpio_direction_output(scl_gpio,1);\r
75                         udelay(5);\r
76                         gpio_direction_output(sda_gpio,1);\r
77                         udelay(5);\r
78 \r
79                         recovered_successfully = 1;\r
80                         break;\r
81                 }\r
82         }\r
83 \r
84         gpio_free(scl_gpio);\r
85         gpio_free(sda_gpio);\r
86 \r
87         if (likely(recovered_successfully)) {\r
88                 pr_err("arbitration lost recovered by re-try-count 0x%08x\n",\r
89                         RETRY_MAX_COUNT - retry);\r
90                 return 0;\r
91         } else {\r
92                 pr_err("Un-recovered arbitration lost.\n");\r
93                 return -EINVAL;\r
94         }\r
95 \r
96 err:\r
97         gpio_free(scl_gpio);\r
98         return ret;\r
99 }\r
100 \r