summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Chauhan <alokc@nvidia.com>2011-08-16 14:35:42 +0530
committerNiket Sirsi <nsirsi@nvidia.com>2011-08-16 16:21:17 -0700
commitb942099aeca50f883472926dd01f9f8d486c5149 (patch)
tree034eef91917e5037c706ae05bfbcf084973b3e5b
parent58ee0aef0b9abb136c13ecb38fd82d3d49e55ff9 (diff)
arm: tegra: Added I2C arbitration lost recovery mechanism
Added the code for arbitration lost recovery mechanism for i2c driver and Initialize gpio number for i2c clock and data as part of platform data. bug 854305 This is cherry pick of change http://git-master/r/#change,43200 in main but hand-merged. Change-Id: I2bf46cf54c04b94174435f3fb9c965b74156dd02 Reviewed-on: http://git-master/r/46288 Reviewed-by: Alok Chauhan <alokc@nvidia.com> Tested-by: Alok Chauhan <alokc@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/board.h1
-rw-r--r--arch/arm/mach-tegra/i2c_error_recovery.c104
3 files changed, 106 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 83381a7fdb3d..a8a4b0150a69 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -14,6 +14,7 @@ obj-y += powergate.o
obj-y += suspend.o
obj-y += fuse.o
obj-y += kfuse.o
+obj-y += i2c_error_recovery.o
ifeq ($(CONFIG_TEGRA_ALSA),y)
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_i2s.o
else
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 8d19c17585c9..89d345ccb14d 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -34,6 +34,7 @@ void tegra_move_framebuffer(unsigned long to, unsigned long from,
unsigned long size);
int tegra_dvfs_rail_disable_by_name(const char *reg_id);
bool is_tegra_debug_uartport_hs(void);
+int arb_lost_recovery(int scl_gpio, int sda_gpio);
extern unsigned long tegra_bootloader_fb_start;
extern unsigned long tegra_bootloader_fb_size;
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 000000000000..bea3133b48c1
--- /dev/null
+++ b/arch/arm/mach-tegra/i2c_error_recovery.c
@@ -0,0 +1,104 @@
+/*
+ * arch/arm/mach-tegra/i2c_error_recovery.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include "gpio-names.h"
+#include "board.h"
+
+#define RETRY_MAX_COUNT (9*8+1) /*I2C controller supports eight-byte burst transfer*/
+
+int arb_lost_recovery(int scl_gpio, int sda_gpio)
+{
+ int ret;
+ int retry = RETRY_MAX_COUNT;
+ int recovered_successfully = 0;
+ int val;
+
+ if ((!scl_gpio) || (!sda_gpio)) {
+ pr_err("not proper input:scl_gpio 0x%08x,"
+ "sda_gpio 0x%08x\n", scl_gpio, sda_gpio);
+ return -EINVAL;;
+ }
+
+ ret = gpio_request(scl_gpio, "scl_gpio");
+ if (ret < 0) {
+ pr_err("error in gpio 0x%08x request 0x%08x\n",
+ scl_gpio, ret);
+ return -EINVAL;;
+ }
+ tegra_gpio_enable(scl_gpio);
+
+ ret = gpio_request(sda_gpio, "sda_gpio");
+ if (ret < 0) {
+ pr_err("error in gpio 0x%08x request 0x%08x\n",
+ sda_gpio, ret);
+ goto err;
+ }
+ tegra_gpio_enable(sda_gpio);
+ gpio_direction_input(sda_gpio);
+
+ while (retry--) {
+ gpio_direction_output(scl_gpio,0);
+ udelay(5);
+ gpio_direction_output(scl_gpio,1);
+ udelay(5);
+
+ /* check whether sda struct low release */
+ val = gpio_get_value(sda_gpio);
+ if (val) {
+ /* send START */
+ gpio_direction_output(sda_gpio,0);
+ udelay(5);
+
+ /* send STOP in next clock cycle */
+ gpio_direction_output(scl_gpio,0);
+ udelay(5);
+ gpio_direction_output(scl_gpio,1);
+ udelay(5);
+ gpio_direction_output(sda_gpio,1);
+ udelay(5);
+
+ recovered_successfully = 1;
+ break;
+ }
+ }
+
+ gpio_free(scl_gpio);
+ tegra_gpio_disable(scl_gpio);
+ gpio_free(sda_gpio);
+ tegra_gpio_disable(sda_gpio);
+
+ if (likely(recovered_successfully)) {
+ pr_err("arbitration lost recovered by re-try-count 0x%08x\n",
+ RETRY_MAX_COUNT - retry);
+ return 0;
+ } else {
+ pr_err("Un-recovered arbitration lost.\n");
+ return -EINVAL;
+ }
+
+err:
+ gpio_free(scl_gpio);
+ tegra_gpio_disable(scl_gpio);
+ return ret;
+}
+