X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fi2c%2Ftegra_i2c.c;h=4be41ddbf057ce41335a61ff992f11320921c004;hb=51dce7d2bfdecd974412634e4a0758ac55edcc00;hp=f4142870b304037273cb405f36e9ad2a39819d4b;hpb=a0573d19885236ba03d412f7788104f75f0dea64;p=u-boot diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index f4142870b3..4be41ddbf0 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -1,26 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Copyright (c) 2010-2011 NVIDIA Corporation * NVIDIA Corporation - * - * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include -#include #include #include +#include +#include +#ifndef CONFIG_TEGRA186 #include #include +#endif #include -#include -#include #include -DECLARE_GLOBAL_DATA_PTR; - enum i2c_type { TYPE_114, TYPE_STD, @@ -30,7 +28,8 @@ enum i2c_type { /* 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; @@ -62,12 +61,35 @@ static void set_packet_mode(struct i2c_bus *i2c_bus) 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) @@ -78,8 +100,7 @@ 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. */ - 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) { /* @@ -94,12 +115,12 @@ 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); - 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. */ @@ -112,7 +133,9 @@ static void i2c_init_controller(struct i2c_bus *i2c_bus) 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( @@ -235,7 +258,7 @@ static int send_recv_packets(struct i2c_bus *i2c_bus, 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; @@ -258,7 +281,7 @@ static int send_recv_packets(struct i2c_bus *i2c_bus, 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; @@ -333,20 +356,34 @@ 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); - 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 @@ -354,13 +391,12 @@ static int tegra_i2c_probe(struct udevice *dev) * 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; @@ -368,9 +404,8 @@ static int tegra_i2c_probe(struct udevice *dev) 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; } @@ -469,7 +504,7 @@ int tegra_i2c_get_dvc_bus(struct udevice **busp) 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; }