Commit e32624ef820f821b94333402788e79979681eb29

Authored by Tom Warren
Committed by Tom Warren
1 parent 702b872894

Tegra: I2C: Add T114 clock support to tegra_i2c driver

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>

Showing 4 changed files with 45 additions and 5 deletions Side-by-side Diff

arch/arm/include/asm/arch-tegra/tegra_i2c.h
... ... @@ -105,6 +105,7 @@
105 105 u32 sl_delay_count; /* 3C: I2C_I2C_SL_DELAY_COUNT */
106 106 u32 reserved_2[4]; /* 40: */
107 107 struct i2c_control control; /* 50 ~ 68 */
  108 + u32 clk_div; /* 6C: I2C_I2C_CLOCK_DIVISOR */
108 109 };
109 110  
110 111 /* bit fields definitions for IO Packet Header 1 format */
... ... @@ -153,6 +154,11 @@
153 154 #define I2C_INT_NO_ACK_MASK (1 << I2C_INT_NO_ACK_SHIFT)
154 155 #define I2C_INT_ARBITRATION_LOST_SHIFT 2
155 156 #define I2C_INT_ARBITRATION_LOST_MASK (1 << I2C_INT_ARBITRATION_LOST_SHIFT)
  157 +
  158 +/* I2C_CLK_DIVISOR_REGISTER */
  159 +#define CLK_DIV_STD_FAST_MODE 0x19
  160 +#define CLK_DIV_HS_MODE 1
  161 +#define CLK_MULT_STD_FAST_MODE 8
156 162  
157 163 /**
158 164 * Returns the bus number of the DVC controller
drivers/i2c/tegra_i2c.c
... ... @@ -46,6 +46,7 @@
46 46 struct i2c_control *control;
47 47 struct i2c_ctlr *regs;
48 48 int is_dvc; /* DVC type, rather than I2C */
  49 + int is_scs; /* single clock source (T114+) */
49 50 int inited; /* bus is inited */
50 51 };
51 52  
52 53  
... ... @@ -88,8 +89,29 @@
88 89 * 16 to get the right frequency.
89 90 */
90 91 clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
91   - i2c_bus->speed * 2 * 8);
  92 + i2c_bus->speed * 2 * 8);
92 93  
  94 + if (i2c_bus->is_scs) {
  95 + /*
  96 + * T114 I2C went to a single clock source for standard/fast and
  97 + * HS clock speeds. The new clock rate setting calculation is:
  98 + * SCL = CLK_SOURCE.I2C /
  99 + * (CLK_MULT_STD_FAST_MODE * (I2C_CLK_DIV_STD_FAST_MODE+1) *
  100 + * I2C FREQUENCY DIVISOR) as per the T114 TRM (sec 30.3.1).
  101 + *
  102 + * NOTE: We do this here, after the initial clock/pll start,
  103 + * because if we read the clk_div reg before the controller
  104 + * is running, we hang, and we need it for the new calc.
  105 + */
  106 + int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
  107 + debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
  108 + clk_div_stdfst_mode);
  109 +
  110 + clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
  111 + CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) *
  112 + i2c_bus->speed * 2);
  113 + }
  114 +
93 115 /* Reset I2C controller. */
94 116 i2c_reset_controller(i2c_bus);
95 117  
96 118  
... ... @@ -352,10 +374,11 @@
352 374 * @param node_list list of nodes to process (any <=0 are ignored)
353 375 * @param count number of nodes to process
354 376 * @param is_dvc 1 if these are DVC ports, 0 if standard I2C
  377 + * @param is_scs 1 if this HW uses a single clock source (T114+)
355 378 * @return 0 if ok, -1 on error
356 379 */
357 380 static int process_nodes(const void *blob, int node_list[], int count,
358   - int is_dvc)
  381 + int is_dvc, int is_scs)
359 382 {
360 383 struct i2c_bus *i2c_bus;
361 384 int i;
... ... @@ -375,6 +398,8 @@
375 398 return -1;
376 399 }
377 400  
  401 + i2c_bus->is_scs = is_scs;
  402 +
378 403 i2c_bus->is_dvc = is_dvc;
379 404 if (is_dvc) {
380 405 i2c_bus->control =
381 406  
382 407  
383 408  
... ... @@ -403,18 +428,25 @@
403 428 const void *blob = gd->fdt_blob;
404 429 int count;
405 430  
406   - /* First get the normal i2c ports */
  431 + /* First check for newer (T114+) I2C ports */
407 432 count = fdtdec_find_aliases_for_id(blob, "i2c",
  433 + COMPAT_NVIDIA_TEGRA114_I2C, node_list,
  434 + TEGRA_I2C_NUM_CONTROLLERS);
  435 + if (process_nodes(blob, node_list, count, 0, 1))
  436 + return;
  437 +
  438 + /* Now get the older (T20/T30) normal I2C ports */
  439 + count = fdtdec_find_aliases_for_id(blob, "i2c",
408 440 COMPAT_NVIDIA_TEGRA20_I2C, node_list,
409 441 TEGRA_I2C_NUM_CONTROLLERS);
410   - if (process_nodes(blob, node_list, count, 0))
  442 + if (process_nodes(blob, node_list, count, 0, 0))
411 443 return;
412 444  
413 445 /* Now look for dvc ports */
414 446 count = fdtdec_add_aliases_for_id(blob, "i2c",
415 447 COMPAT_NVIDIA_TEGRA20_DVC, node_list,
416 448 TEGRA_I2C_NUM_CONTROLLERS);
417   - if (process_nodes(blob, node_list, count, 1))
  449 + if (process_nodes(blob, node_list, count, 1, 0))
418 450 return;
419 451 }
420 452  
... ... @@ -62,6 +62,7 @@
62 62 enum fdt_compat_id {
63 63 COMPAT_UNKNOWN,
64 64 COMPAT_NVIDIA_TEGRA20_USB, /* Tegra20 USB port */
  65 + COMPAT_NVIDIA_TEGRA114_I2C, /* Tegra114 I2C w/single clock source */
65 66 COMPAT_NVIDIA_TEGRA20_I2C, /* Tegra20 i2c */
66 67 COMPAT_NVIDIA_TEGRA20_DVC, /* Tegra20 dvc (really just i2c) */
67 68 COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */
... ... @@ -37,6 +37,7 @@
37 37 static const char * const compat_names[COMPAT_COUNT] = {
38 38 COMPAT(UNKNOWN, "<none>"),
39 39 COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
  40 + COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
40 41 COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
41 42 COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
42 43 COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),