mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-06 20:09:32 +00:00
i2c: tegra: add standardized clk/reset API support
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>
This commit is contained in:
parent
bbc5b36b25
commit
3c27fa2193
1 changed files with 85 additions and 4 deletions
|
@ -12,13 +12,27 @@
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
#ifdef CONFIG_TEGRA186
|
||||||
|
#include <clk.h>
|
||||||
|
#include <reset.h>
|
||||||
|
#else
|
||||||
#include <asm/arch/clock.h>
|
#include <asm/arch/clock.h>
|
||||||
#include <asm/arch/funcmux.h>
|
#include <asm/arch/funcmux.h>
|
||||||
#include <asm/arch/gpio.h>
|
|
||||||
#include <asm/arch/pinmux.h>
|
#include <asm/arch/pinmux.h>
|
||||||
#include <asm/arch-tegra/clk_rst.h>
|
#include <asm/arch-tegra/clk_rst.h>
|
||||||
|
#endif
|
||||||
|
#include <asm/arch/gpio.h>
|
||||||
#include <asm/arch-tegra/tegra_i2c.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;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
enum i2c_type {
|
enum i2c_type {
|
||||||
|
@ -30,7 +44,12 @@ enum i2c_type {
|
||||||
/* Information about i2c controller */
|
/* Information about i2c controller */
|
||||||
struct i2c_bus {
|
struct i2c_bus {
|
||||||
int id;
|
int id;
|
||||||
|
#ifdef CONFIG_TEGRA186
|
||||||
|
struct reset_ctl reset_ctl;
|
||||||
|
struct clk clk;
|
||||||
|
#else
|
||||||
enum periph_id periph_id;
|
enum periph_id periph_id;
|
||||||
|
#endif
|
||||||
int speed;
|
int speed;
|
||||||
int pinmux_config;
|
int pinmux_config;
|
||||||
struct i2c_control *control;
|
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)
|
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
|
||||||
{
|
{
|
||||||
/* Reset I2C controller. */
|
/* 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);
|
reset_periph(i2c_bus->periph_id, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* re-program config register to packet mode */
|
/* re-program config register to packet mode */
|
||||||
set_packet_mode(i2c_bus);
|
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)
|
static void i2c_init_controller(struct i2c_bus *i2c_bus)
|
||||||
{
|
{
|
||||||
if (!i2c_bus->speed)
|
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
|
* here, in section 23.3.1, but in fact we seem to need a factor of
|
||||||
* 16 to get the right frequency.
|
* 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,
|
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
|
||||||
i2c_bus->speed * 2 * 8);
|
i2c_bus->speed * 2 * 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (i2c_bus->type == TYPE_114) {
|
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.
|
* is running, we hang, and we need it for the new calc.
|
||||||
*/
|
*/
|
||||||
int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
|
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__,
|
debug("%s: CLK_DIV_STD_FAST_MODE setting = %d\n", __func__,
|
||||||
clk_div_stdfst_mode);
|
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,
|
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
|
||||||
CLK_MULT_STD_FAST_MODE * (clk_div_stdfst_mode + 1) *
|
rate);
|
||||||
i2c_bus->speed * 2);
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset I2C controller. */
|
/* 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);
|
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);
|
funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_packet_headers(
|
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)
|
static int tegra_i2c_probe(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct i2c_bus *i2c_bus = dev_get_priv(dev);
|
struct i2c_bus *i2c_bus = dev_get_priv(dev);
|
||||||
|
#ifdef CONFIG_TEGRA186
|
||||||
|
int ret;
|
||||||
|
#else
|
||||||
const void *blob = gd->fdt_blob;
|
const void *blob = gd->fdt_blob;
|
||||||
int node = dev->of_offset;
|
int node = dev->of_offset;
|
||||||
|
#endif
|
||||||
bool is_dvc;
|
bool is_dvc;
|
||||||
|
|
||||||
i2c_bus->id = dev->seq;
|
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
|
* We don't have a binding for pinmux yet. Leave it out for now. So
|
||||||
* far no one needs anything other than the default.
|
* 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->pinmux_config = FUNCMUX_DEFAULT;
|
||||||
i2c_bus->periph_id = clock_decode_periph_id(blob, node);
|
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)
|
if (i2c_bus->periph_id == -1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
#endif
|
||||||
|
|
||||||
is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
|
is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
|
||||||
if (is_dvc) {
|
if (is_dvc) {
|
||||||
|
@ -370,7 +446,12 @@ static int tegra_i2c_probe(struct udevice *dev)
|
||||||
i2c_init_controller(i2c_bus);
|
i2c_init_controller(i2c_bus);
|
||||||
debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
|
debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
|
||||||
is_dvc ? "dvc" : "i2c", dev->seq, i2c_bus->regs,
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue