public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Tom Warren <twarren.nvidia@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 1/3] Tegra: I2C: Add T114 clock support to tegra_i2c driver
Date: Fri,  8 Feb 2013 10:25:30 -0700	[thread overview]
Message-ID: <1360344332-14664-2-git-send-email-twarren@nvidia.com> (raw)
In-Reply-To: <1360344332-14664-1-git-send-email-twarren@nvidia.com>

T114 has a slightly different I2C clock, with a new (extra) divisor
in standard/fast mode and HS mode. Tested on my Dalmore, and the I2C
clock is 100KHz +/- 3Hz on my Saleae Logic analyzer.

Added a new entry in compat_names for T114 I2C since it differs
from the previous Tegra SoCs. A flag is set when T114 I2C HW is
found so new features like the extra clock divisor can be used.

Signed-off-by: Tom Warren <twarren@nvidia.com>
Acked-by: Laxman Dewangan <ldewangan@nvidia.com>
---
v2: new
V3:
- Added tegra114-i2c name to compat_names/compat_id table(s)
- Add search for T114 I2C node in i2c_init_board
- Added is_scs flag to i2c_bus struct (single clock source HW)
- Use is_scs flag to trigger new clock source rate calculation
    
 arch/arm/include/asm/arch-tegra/tegra_i2c.h |    6 ++++
 drivers/i2c/tegra_i2c.c                     |   42 +++++++++++++++++++++++---
 include/fdtdec.h                            |    1 +
 lib/fdtdec.c                                |    1 +
 4 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
index 2650744..853e59b 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h
@@ -105,6 +105,7 @@ struct i2c_ctlr {
 	u32 sl_delay_count;		/* 3C: I2C_I2C_SL_DELAY_COUNT */
 	u32 reserved_2[4];		/* 40: */
 	struct i2c_control control;	/* 50 ~ 68 */
+	u32 clk_div;			/* 6C: I2C_I2C_CLOCK_DIVISOR */
 };
 
 /* bit fields definitions for IO Packet Header 1 format */
@@ -154,6 +155,11 @@ struct i2c_ctlr {
 #define I2C_INT_ARBITRATION_LOST_SHIFT	2
 #define I2C_INT_ARBITRATION_LOST_MASK	(1 << I2C_INT_ARBITRATION_LOST_SHIFT)
 
+/* I2C_CLK_DIVISOR_REGISTER */
+#define CLK_DIV_STD_FAST_MODE		0x19
+#define CLK_DIV_HS_MODE			1
+#define CLK_MULT_STD_FAST_MODE		8
+
 /**
  * Returns the bus number of the DVC controller
  *
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index efc77fa..ca71cd3 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -46,6 +46,7 @@ struct i2c_bus {
 	struct i2c_control	*control;
 	struct i2c_ctlr		*regs;
 	int			is_dvc;	/* DVC type, rather than I2C */
+	int			is_scs;	/* single clock source (T114+) */
 	int			inited;	/* bus is inited */
 };
 
@@ -88,7 +89,28 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
 	 * 16 to get the right frequency.
 	 */
 	clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
-			       i2c_bus->speed * 2 * 8);
+		i2c_bus->speed * 2 * 8);
+
+	if (i2c_bus->is_scs) {
+		/*
+		 * T114 I2C went to a single clock source for standard/fast and
+		 * HS clock speeds. The new clock rate setting calculation is:
+		 *  SCL = CLK_SOURCE.I2C /
+		 *   (CLK_MULT_STD_FAST_MODE * (I2C_CLK_DIV_STD_FAST_MODE+1) *
+		 *   I2C FREQUENCY DIVISOR) as per the T114 TRM (sec 30.3.1).
+		 *
+		 * NOTE: We do this here, after the initial clock/pll start,
+		 * because if we read the clk_div reg before the controller
+		 * is running, we hang, and we need it for the new calc.
+		 */
+		int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
+		debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
+			clk_div_stdfst_mode);
+
+		clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
+			CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) *
+			i2c_bus->speed * 2);
+	}
 
 	/* Reset I2C controller. */
 	i2c_reset_controller(i2c_bus);
@@ -352,10 +374,11 @@ static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
  * @param node_list	list of nodes to process (any <=0 are ignored)
  * @param count		number of nodes to process
  * @param is_dvc	1 if these are DVC ports, 0 if standard I2C
+ * @param is_scs	1 if this HW uses a single clock source (T114+)
  * @return 0 if ok, -1 on error
  */
 static int process_nodes(const void *blob, int node_list[], int count,
-			 int is_dvc)
+			 int is_dvc, int is_scs)
 {
 	struct i2c_bus *i2c_bus;
 	int i;
@@ -375,6 +398,8 @@ static int process_nodes(const void *blob, int node_list[], int count,
 			return -1;
 		}
 
+		i2c_bus->is_scs = is_scs;
+
 		i2c_bus->is_dvc = is_dvc;
 		if (is_dvc) {
 			i2c_bus->control =
@@ -403,18 +428,25 @@ void i2c_init_board(void)
 	const void *blob = gd->fdt_blob;
 	int count;
 
-	/* First get the normal i2c ports */
+	/* First check for newer (T114+) I2C ports */
+	count = fdtdec_find_aliases_for_id(blob, "i2c",
+			COMPAT_NVIDIA_TEGRA114_I2C, node_list,
+			TEGRA_I2C_NUM_CONTROLLERS);
+	if (process_nodes(blob, node_list, count, 0, 1))
+		return;
+
+	/* Now get the older (T20/T30) normal I2C ports */
 	count = fdtdec_find_aliases_for_id(blob, "i2c",
 			COMPAT_NVIDIA_TEGRA20_I2C, node_list,
 			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 0))
+	if (process_nodes(blob, node_list, count, 0, 0))
 		return;
 
 	/* Now look for dvc ports */
 	count = fdtdec_add_aliases_for_id(blob, "i2c",
 			COMPAT_NVIDIA_TEGRA20_DVC, node_list,
 			TEGRA_I2C_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count, 1))
+	if (process_nodes(blob, node_list, count, 1, 0))
 		return;
 }
 
diff --git a/include/fdtdec.h b/include/fdtdec.h
index f77d195..5abf9e7 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -62,6 +62,7 @@ struct fdt_memory {
 enum fdt_compat_id {
 	COMPAT_UNKNOWN,
 	COMPAT_NVIDIA_TEGRA20_USB,	/* Tegra20 USB port */
+	COMPAT_NVIDIA_TEGRA114_I2C,	/* Tegra114 I2C w/single clock source */
 	COMPAT_NVIDIA_TEGRA20_I2C,	/* Tegra20 i2c */
 	COMPAT_NVIDIA_TEGRA20_DVC,	/* Tegra20 dvc (really just i2c) */
 	COMPAT_NVIDIA_TEGRA20_EMC,	/* Tegra20 memory controller */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 16921e1..2681d74 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -37,6 +37,7 @@ DECLARE_GLOBAL_DATA_PTR;
 static const char * const compat_names[COMPAT_COUNT] = {
 	COMPAT(UNKNOWN, "<none>"),
 	COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
+	COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
 	COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
 	COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
 	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
-- 
1.7.0.4

  reply	other threads:[~2013-02-08 17:25 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-02-08 17:25 [U-Boot] [PATCH v3 0/3] Add I2C driver for T114 Dalmore Tom Warren
2013-02-08 17:25 ` Tom Warren [this message]
2013-02-08 17:25 ` [U-Boot] [PATCH v3 2/3] Tegra114: fdt: Update DT files with I2C info for T114/Dalmore Tom Warren
2013-02-08 18:04   ` Stephen Warren
2013-02-12 12:02     ` Laxman Dewangan
2013-02-12 17:40       ` Tom Warren
2013-02-12 18:10         ` Stephen Warren
2013-02-12 19:07           ` Tom Warren
2013-02-14 22:40             ` Tom Warren
2013-02-08 17:25 ` [U-Boot] [PATCH v3 3/3] Tegra114: I2C: Enable I2C driver on Dalmore E1611 eval board Tom Warren
2013-02-12 18:15 ` [U-Boot] [PATCH v3 0/3] Add I2C driver for T114 Dalmore Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1360344332-14664-2-git-send-email-twarren@nvidia.com \
    --to=twarren.nvidia@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox