]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/i2c/tegra_i2c.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[people/ms/u-boot.git] / drivers / i2c / tegra_i2c.c
index e3be14e3cf3156a349bbf6abd03c520cd9b1d3aa..e96d5d5d090423c71feb4fa7e683862219d2b1be 100644 (file)
@@ -3,35 +3,19 @@
  * Copyright (c) 2010-2011 NVIDIA Corporation
  *  NVIDIA Corporation <www.nvidia.com>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <asm/io.h>
-#include <asm/arch/clk_rst.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/funcmux.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
-#include <asm/arch/tegra_i2c.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/tegra_i2c.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -46,6 +30,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 +73,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 +358,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 +382,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 +412,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;
 }