+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Copyright (c) 2010-2011 NVIDIA Corporation
* NVIDIA Corporation <www.nvidia.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
-#include <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
+#include <clk.h>
+#include <reset.h>
+#ifndef CONFIG_TEGRA186
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
+#endif
#include <asm/arch/gpio.h>
-#include <asm/arch/pinmux.h>
-#include <asm/arch-tegra/clk_rst.h>
#include <asm/arch-tegra/tegra_i2c.h>
-DECLARE_GLOBAL_DATA_PTR;
-
enum i2c_type {
TYPE_114,
TYPE_STD,
/* Information about i2c controller */
struct i2c_bus {
int id;
- enum periph_id periph_id;
+ struct reset_ctl reset_ctl;
+ struct clk clk;
int speed;
int pinmux_config;
struct i2c_control *control;
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
- reset_periph(i2c_bus->periph_id, 1);
+ reset_assert(&i2c_bus->reset_ctl);
+ udelay(1);
+ reset_deassert(&i2c_bus->reset_ctl);
+ udelay(1);
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
+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;
+}
+
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
if (!i2c_bus->speed)
* here, in section 23.3.1, but in fact we seem to need a factor of
* 16 to get the right frequency.
*/
- clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
- i2c_bus->speed * 2 * 8);
+ i2c_init_clock(i2c_bus, i2c_bus->speed * 2 * 8);
if (i2c_bus->type == TYPE_114) {
/*
* 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);
- 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);
+ i2c_init_clock(i2c_bus, rate);
}
/* Reset I2C controller. */
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
- funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
+#ifndef CONFIG_TEGRA186
+ funcmux_select(i2c_bus->clk.id, i2c_bus->pinmux_config);
+#endif
}
static void send_packet_headers(
if ((words == 1) && last_bytes) {
local = 0;
memcpy(&local, dptr, last_bytes);
- } else if ((unsigned)dptr & 3) {
+ } else if ((unsigned long)dptr & 3) {
memcpy(&local, dptr, sizeof(u32));
} else {
local = *wptr;
local = readl(&control->rx_fifo);
if ((words == 1) && last_bytes)
memcpy(dptr, (char *)&local, last_bytes);
- else if ((unsigned)dptr & 3)
+ else if ((unsigned long)dptr & 3)
memcpy(dptr, &local, sizeof(u32));
else
*wptr = local;
static int tegra_i2c_probe(struct udevice *dev)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
- const void *blob = gd->fdt_blob;
- int node = dev->of_offset;
+ int ret;
bool is_dvc;
i2c_bus->id = dev->seq;
- i2c_bus->type = dev_get_of_data(dev);
- i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
+ i2c_bus->type = dev_get_driver_data(dev);
+ i2c_bus->regs = (struct i2c_ctlr *)dev_read_addr(dev);
+ if ((ulong)i2c_bus->regs == FDT_ADDR_T_NONE) {
+ debug("%s: Cannot get regs address\n", __func__);
+ return -EINVAL;
+ }
+ ret = reset_get_by_name(dev, "i2c", &i2c_bus->reset_ctl);
+ if (ret) {
+ pr_err("reset_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+ ret = clk_get_by_name(dev, "div-clk", &i2c_bus->clk);
+ if (ret) {
+ pr_err("clk_get_by_name() failed: %d\n", ret);
+ return ret;
+ }
+
+#ifndef CONFIG_TEGRA186
/*
* We don't have a binding for pinmux yet. Leave it out for now. So
* far no one needs anything other than the default.
*/
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
- i2c_bus->periph_id = clock_decode_periph_id(blob, node);
/*
* We can't specify the pinmux config in the fdt, so I2C2 will not
* You could add in this little hack if you need to use it.
* The correct solution is a pinmux binding in the fdt.
*
- * if (i2c_bus->periph_id == PERIPH_ID_I2C2)
+ * if (i2c_bus->clk.id == PERIPH_ID_I2C2)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
- if (i2c_bus->periph_id == -1)
- return -EINVAL;
+#endif
- is_dvc = dev_get_of_data(dev) == TYPE_DVC;
+ is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
i2c_bus->control = &i2c_bus->regs->control;
}
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);
+ debug("%s: controller bus %d at %p, speed %d: ",
+ is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs, i2c_bus->speed);
return 0;
}
for (uclass_first_device(UCLASS_I2C, &bus);
bus;
uclass_next_device(&bus)) {
- if (dev_get_of_data(bus) == TYPE_DVC) {
+ if (dev_get_driver_data(bus) == TYPE_DVC) {
*busp = bus;
return 0;
}