i2c: tegra: add standardized clk/reset API support
authorBryan Wu <pengw@nvidia.com>
Fri, 5 Aug 2016 22:10:35 +0000 (16:10 -0600)
committerTom Warren <twarren@nvidia.com>
Mon, 15 Aug 2016 17:26:13 +0000 (10:26 -0700)
clk/reset API was tested on T186 platform and previous chip like
T210/T124 will still use the old APIs.

Signed-off-by: Bryan Wu <pengw@nvidia.com>
(swarren, simplified some ifdefs, removed indent level inside an ifdef)
(swarren, added comment about the ifdefs)
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Heiko Schocher <hs@denx.de>
Signed-off-by: Tom Warren <twarren@nvidia.com>
drivers/i2c/tegra_i2c.c

index 2fa07f9c57c455d96121183eff05c02ba7d72b40..31ba263b72952177679db7650126616ac207ad2c 100644 (file)
 #include <fdtdec.h>
 #include <i2c.h>
 #include <asm/io.h>
+#ifdef CONFIG_TEGRA186
+#include <clk.h>
+#include <reset.h>
+#else
 #include <asm/arch/clock.h>
 #include <asm/arch/funcmux.h>
-#include <asm/arch/gpio.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch-tegra/clk_rst.h>
+#endif
+#include <asm/arch/gpio.h>
 #include <asm/arch-tegra/tegra_i2c.h>
 
+/*
+ * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that
+ * should not be present. These are needed because newer Tegra SoCs support
+ * only the standard clock/reset APIs, whereas older Tegra SoCs support only
+ * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be
+ * fixed to implement the standard APIs, and all drivers converted to solely
+ * use the new standard APIs, with no ifdefs.
+ */
+
 DECLARE_GLOBAL_DATA_PTR;
 
 enum i2c_type {
@@ -30,7 +44,12 @@ enum i2c_type {
 /* Information about i2c controller */
 struct i2c_bus {
        int                     id;
+#ifdef CONFIG_TEGRA186
+       struct reset_ctl        reset_ctl;
+       struct clk              clk;
+#else
        enum periph_id          periph_id;
+#endif
        int                     speed;
        int                     pinmux_config;
        struct i2c_control      *control;
@@ -62,12 +81,41 @@ static void set_packet_mode(struct i2c_bus *i2c_bus)
 static void i2c_reset_controller(struct i2c_bus *i2c_bus)
 {
        /* Reset I2C controller. */
+#ifdef CONFIG_TEGRA186
+       reset_assert(&i2c_bus->reset_ctl);
+       udelay(1);
+       reset_deassert(&i2c_bus->reset_ctl);
+       udelay(1);
+#else
        reset_periph(i2c_bus->periph_id, 1);
+#endif
 
        /* re-program config register to packet mode */
        set_packet_mode(i2c_bus);
 }
 
+#ifdef CONFIG_TEGRA186
+static int i2c_init_clock(struct i2c_bus *i2c_bus, unsigned rate)
+{
+       int ret;
+
+       ret = reset_assert(&i2c_bus->reset_ctl);
+       if (ret)
+               return ret;
+       ret = clk_enable(&i2c_bus->clk);
+       if (ret)
+               return ret;
+       ret = clk_set_rate(&i2c_bus->clk, rate);
+       if (IS_ERR_VALUE(ret))
+               return ret;
+       ret = reset_deassert(&i2c_bus->reset_ctl);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+#endif
+
 static void i2c_init_controller(struct i2c_bus *i2c_bus)
 {
        if (!i2c_bus->speed)
@@ -78,8 +126,12 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
         * here, in section 23.3.1, but in fact we seem to need a factor of
         * 16 to get the right frequency.
         */
+#ifdef CONFIG_TEGRA186
+       i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
+#else
        clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
                i2c_bus->speed * 2 * 8);
+#endif
 
        if (i2c_bus->type == TYPE_114) {
                /*
@@ -94,12 +146,17 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
                 * is running, we hang, and we need it for the new calc.
                 */
                int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
+               unsigned rate = CLK_MULT_STD_FAST_MODE *
+                               (clk_div_stdfst_mode + 1) * i2c_bus->speed * 2;
                debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
                        clk_div_stdfst_mode);
 
+#ifdef CONFIG_TEGRA186
+               i2c_init_clock(i2c_bus, rate);
+#else
                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);
+                                      rate);
+#endif
        }
 
        /* Reset I2C controller. */
@@ -112,7 +169,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus)
                setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
        }
 
+#ifndef CONFIG_TEGRA186
        funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
+#endif
 }
 
 static void send_packet_headers(
@@ -333,8 +392,12 @@ static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 static int tegra_i2c_probe(struct udevice *dev)
 {
        struct i2c_bus *i2c_bus = dev_get_priv(dev);
+#ifdef CONFIG_TEGRA186
+       int ret;
+#else
        const void *blob = gd->fdt_blob;
        int node = dev->of_offset;
+#endif
        bool is_dvc;
 
        i2c_bus->id = dev->seq;
@@ -345,6 +408,18 @@ static int tegra_i2c_probe(struct udevice *dev)
         * We don't have a binding for pinmux yet. Leave it out for now. So
         * far no one needs anything other than the default.
         */
+#ifdef CONFIG_TEGRA186
+       ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
+       if (ret) {
+               error("reset_get_by_name() failed: %d\n", ret);
+               return ret;
+       }
+       ret = clk_get_by_name(dev, "i2c", &i2c_bus->clk);
+       if (ret) {
+               error("clk_get_by_name() failed: %d\n", ret);
+               return ret;
+       }
+#else
        i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
        i2c_bus->periph_id = clock_decode_periph_id(blob, node);
 
@@ -359,6 +434,7 @@ static int tegra_i2c_probe(struct udevice *dev)
         */
        if (i2c_bus->periph_id == -1)
                return -EINVAL;
+#endif
 
        is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
        if (is_dvc) {
@@ -370,7 +446,12 @@ static int tegra_i2c_probe(struct udevice *dev)
        i2c_init_controller(i2c_bus);
        debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
              is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
-             i2c_bus->periph_id, i2c_bus->speed);
+#ifndef CONFIG_TEGRA186
+             i2c_bus->periph_id,
+#else
+             -1,
+#endif
+             i2c_bus->speed);
 
        return 0;
 }