diff mbox

[U-Boot,3/5] i2c: tegra: add standardized clk/reset API support

Message ID 20160727214822.26697-3-swarren@wwwdotorg.org
State Superseded
Delegated to: Tom Warren
Headers show

Commit Message

Stephen Warren July 27, 2016, 9:48 p.m. UTC
From: Bryan Wu <pengw@nvidia.com>

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)
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Cc: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/tegra_i2c.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 76 insertions(+), 4 deletions(-)

Comments

Simon Glass Aug. 1, 2016, 1:02 a.m. UTC | #1
Hi Stephen,

On 27 July 2016 at 15:48, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Bryan Wu <pengw@nvidia.com>
>
> 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)
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> Cc: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/tegra_i2c.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 76 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
> index 2fa07f9c57c4..b8cb24ec87d5 100644
> --- a/drivers/i2c/tegra_i2c.c
> +++ b/drivers/i2c/tegra_i2c.c
> @@ -12,11 +12,16 @@
>  #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>
>
>  DECLARE_GLOBAL_DATA_PTR;
> @@ -30,7 +35,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

This doesn't seem right - the drivers should be SoC-independent at compile-time.


>         int                     speed;
>         int                     pinmux_config;
>         struct i2c_control      *control;
> @@ -62,12 +72,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 +117,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 +137,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 +160,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 +383,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 +399,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 +425,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 +437,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,

Probably the concept of periph_id can go away now? Perhaps this driver
needs a clean-up?

> +#else
> +             -1,
> +#endif
> +             i2c_bus->speed);
>
>         return 0;
>  }
> --
> 2.9.2
>

Regards,
Simon
diff mbox

Patch

diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 2fa07f9c57c4..b8cb24ec87d5 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -12,11 +12,16 @@ 
 #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>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -30,7 +35,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 +72,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 +117,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 +137,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 +160,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 +383,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 +399,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 +425,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 +437,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;
 }