diff options
author | Alok Chauhan <alokc@nvidia.com> | 2011-07-26 16:00:32 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-08-09 16:01:48 -0700 |
commit | c7f57cc760411c030dd0fae88e2b78bf8439791f (patch) | |
tree | c906d914fd255ecc33fe4eb57d0b7bef9207dd00 /arch/arm/mach-tegra | |
parent | c6b3cd0903bb29bca54daa83c183d6f20ee6bc90 (diff) |
arm: tegra: cardhu: 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
Change-Id: Icdc243a5025c766d65816542a6d5aabd61e6eee1
Reviewed-on: http://git-master/r/43200
Reviewed-by: Bandi Krishna Chaitanya <bandik@nvidia.com>
Tested-by: Bandi Krishna Chaitanya <bandik@nvidia.com>
Reviewed-by: Alok Chauhan <alokc@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-cardhu.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-enterprise.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/i2c_error_recovery.c | 104 |
5 files changed, 136 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 72e0f0dcf64f..ba9705104902 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -24,6 +24,7 @@ obj-y += suspend.o obj-y += fuse.o obj-y += kfuse.o obj-y += tegra_odm_fuses.o +obj-y += i2c_error_recovery.o ifeq ($(CONFIG_TEGRA_ALSA),y) obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_i2s.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra3_i2s.o diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c index 6bc52d7b1a85..c0536c9c5bdb 100644 --- a/arch/arm/mach-tegra/board-cardhu.c +++ b/arch/arm/mach-tegra/board-cardhu.c @@ -339,6 +339,9 @@ static struct tegra_i2c_platform_data cardhu_i2c1_platform_data = { .adapter_nr = 0, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PC4, + .sda_gpio = TEGRA_GPIO_PC5, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data cardhu_i2c2_platform_data = { @@ -346,24 +349,36 @@ static struct tegra_i2c_platform_data cardhu_i2c2_platform_data = { .bus_count = 1, .bus_clk_rate = { 100000, 0 }, .is_clkon_always = true, + .scl_gpio = TEGRA_GPIO_PT5, + .sda_gpio = TEGRA_GPIO_PT6, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data cardhu_i2c3_platform_data = { .adapter_nr = 2, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PBB1, + .sda_gpio = TEGRA_GPIO_PBB2, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data cardhu_i2c4_platform_data = { .adapter_nr = 3, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PV4, + .sda_gpio = TEGRA_GPIO_PV5, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data cardhu_i2c5_platform_data = { .adapter_nr = 4, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PZ6, + .sda_gpio = TEGRA_GPIO_PZ7, + .arb_recovery = arb_lost_recovery, }; static struct tegra_audio_platform_data tegra_i2s_pdata[] = { diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c index 24bc5af7eeee..237c79116064 100644 --- a/arch/arm/mach-tegra/board-enterprise.c +++ b/arch/arm/mach-tegra/board-enterprise.c @@ -406,6 +406,9 @@ static struct tegra_i2c_platform_data enterprise_i2c1_platform_data = { .adapter_nr = 0, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PC4, + .sda_gpio = TEGRA_GPIO_PC5, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data enterprise_i2c2_platform_data = { @@ -413,24 +416,36 @@ static struct tegra_i2c_platform_data enterprise_i2c2_platform_data = { .bus_count = 1, .bus_clk_rate = { 100000, 0 }, .is_clkon_always = true, + .scl_gpio = TEGRA_GPIO_PT5, + .sda_gpio = TEGRA_GPIO_PT6, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data enterprise_i2c3_platform_data = { .adapter_nr = 2, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PBB1, + .sda_gpio = TEGRA_GPIO_PBB2, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data enterprise_i2c4_platform_data = { .adapter_nr = 3, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PV4, + .sda_gpio = TEGRA_GPIO_PV5, + .arb_recovery = arb_lost_recovery, }; static struct tegra_i2c_platform_data enterprise_i2c5_platform_data = { .adapter_nr = 4, .bus_count = 1, .bus_clk_rate = { 100000, 0 }, + .scl_gpio = TEGRA_GPIO_PZ6, + .sda_gpio = TEGRA_GPIO_PZ7, + .arb_recovery = arb_lost_recovery, }; static struct tegra_audio_platform_data tegra_i2s_pdata[] = { diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index bc63e20c1981..a15834f8e7ee 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -37,6 +37,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;
+}
+
|