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