avionic design with actual uboot and tooling

submodule of avionic design uboot bootloader and with included tools to
get you started , read readme.md and readme-tk1-loader.md
This commit is contained in:
2026-03-03 21:46:32 +02:00
parent fe3ba02c96
commit 68d74d3181
11967 changed files with 2221897 additions and 0 deletions

159
u-boot/drivers/i2c/Kconfig Normal file
View File

@@ -0,0 +1,159 @@
#
# I2C subsystem configuration
#
menu "I2C support"
config DM_I2C
bool "Enable Driver Model for I2C drivers"
depends on DM
help
Enable driver model for I2C. The I2C uclass interface: probe, read,
write and speed, is implemented with the bus drivers operations,
which provide methods for bus setting and data transfer. Each chip
device (bus child) info is kept as parent platdata. The interface
is defined in include/i2c.h. When i2c bus driver supports the i2c
uclass, but the device drivers not, then DM_I2C_COMPAT config can
be used as compatibility layer.
config DM_I2C_COMPAT
bool "Enable I2C compatibility layer"
depends on DM
help
Enable old-style I2C functions for compatibility with existing code.
This option can be enabled as a temporary measure to avoid needing
to convert all code for a board in a single commit. It should not
be enabled for any board in an official release.
config I2C_CROS_EC_TUNNEL
tristate "Chrome OS EC tunnel I2C bus"
depends on CROS_EC
help
This provides an I2C bus that will tunnel i2c commands through to
the other side of the Chrome OS EC to the I2C bus connected there.
This will work whatever the interface used to talk to the EC (SPI,
I2C or LPC). Some Chromebooks use this when the hardware design
does not allow direct access to the main PMIC from the AP.
config I2C_CROS_EC_LDO
bool "Provide access to LDOs on the Chrome OS EC"
depends on CROS_EC
---help---
On many Chromebooks the main PMIC is inaccessible to the AP. This is
often dealt with by using an I2C pass-through interface provided by
the EC. On some unfortunate models (e.g. Spring) the pass-through
is not available, and an LDO message is available instead. This
option enables a driver which provides very basic access to those
regulators, via the EC. We implement this as an I2C bus which
emulates just the TPS65090 messages we know about. This is done to
avoid duplicating the logic in the TPS65090 regulator driver for
enabling/disabling an LDO.
config DM_I2C_GPIO
bool "Enable Driver Model for software emulated I2C bus driver"
depends on DM_I2C && DM_GPIO
help
Enable the i2c bus driver emulation by using the GPIOs. The bus GPIO
configuration is given by the device tree. Kernel-style device tree
bindings are supported.
Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
config SYS_I2C_FSL
bool "Freescale I2C bus driver"
depends on DM_I2C
help
Add support for Freescale I2C busses as used on MPC8240, MPC8245, and
MPC85xx processors.
config SYS_I2C_CADENCE
tristate "Cadence I2C Controller"
depends on DM_I2C && (ARCH_ZYNQ || ARM64)
help
Say yes here to select Cadence I2C Host Controller. This controller is
e.g. used by Xilinx Zynq.
config SYS_I2C_DW
bool "Designware I2C Controller"
default n
help
Say yes here to select the Designware I2C Host Controller. This
controller is used in various SoCs, e.g. the ST SPEAr, Altera
SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs.
config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
bool "DW I2C Enable Status Register not supported"
depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \
TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600)
default y
help
Some versions of the Designware I2C controller do not support the
enable status register. This config option can be enabled in such
cases.
config SYS_I2C_INTEL
bool "Intel I2C/SMBUS driver"
depends on DM_I2C
help
Add support for the Intel SMBUS driver. So far this driver is just
a stub which perhaps some basic init. There is no implementation of
the I2C API meaning that any I2C operations will immediately fail
for now.
config SYS_I2C_ROCKCHIP
bool "Rockchip I2C driver"
depends on DM_I2C
help
Add support for the Rockchip I2C driver. This is used with various
Rockchip parts such as RK3126, RK3128, RK3036 and RK3288. All chips
have several I2C ports and all are provided, controled by the
device tree.
config SYS_I2C_SANDBOX
bool "Sandbox I2C driver"
depends on SANDBOX && DM_I2C
help
Enable I2C support for sandbox. This is an emulation of a real I2C
bus. Devices can be attached to the bus using the device tree
which specifies the driver to use. As an example, see this device
tree fragment from sandbox.dts. It shows that the I2C bus has a
single EEPROM at address 0x2c (7-bit address) which is emulated by
the driver for "sandbox,i2c-eeprom", which is in
drivers/misc/i2c_eeprom_emul.c.
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
compatible = "sandbox,i2c";
clock-frequency = <400000>;
eeprom@2c {
reg = <0x2c>;
compatible = "i2c-eeprom";
emul {
compatible = "sandbox,i2c-eeprom";
sandbox,filename = "i2c.bin";
sandbox,size = <128>;
};
};
};
config SYS_I2C_UNIPHIER
bool "UniPhier I2C driver"
depends on ARCH_UNIPHIER && DM_I2C
default y
help
Support for UniPhier I2C controller driver. This I2C controller
is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs.
config SYS_I2C_UNIPHIER_F
bool "UniPhier FIFO-builtin I2C driver"
depends on ARCH_UNIPHIER && DM_I2C
default y
help
Support for UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
source "drivers/i2c/muxes/Kconfig"
endmenu

View File

@@ -0,0 +1,45 @@
#
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o
obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o
obj-$(CONFIG_SYS_I2C) += i2c_core.o
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o
obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o
obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o
obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o
obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
obj-$(CONFIG_I2C_MUX) += muxes/

View File

@@ -0,0 +1,306 @@
/*
* i2c.c - driver for ADI TWI/I2C
*
* Copyright (c) 2006-2014 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <console.h>
#include <i2c.h>
#include <asm/clock.h>
#include <asm/twi.h>
#include <asm/io.h>
static struct twi_regs *i2c_get_base(struct i2c_adapter *adap);
/* Every register is 32bit aligned, but only 16bits in size */
#define ureg(name) u16 name; u16 __pad_##name;
struct twi_regs {
ureg(clkdiv);
ureg(control);
ureg(slave_ctl);
ureg(slave_stat);
ureg(slave_addr);
ureg(master_ctl);
ureg(master_stat);
ureg(master_addr);
ureg(int_stat);
ureg(int_mask);
ureg(fifo_ctl);
ureg(fifo_stat);
char __pad[0x50];
ureg(xmt_data8);
ureg(xmt_data16);
ureg(rcv_data8);
ureg(rcv_data16);
};
#undef ureg
#ifdef TWI_CLKDIV
#define TWI0_CLKDIV TWI_CLKDIV
# ifdef CONFIG_SYS_MAX_I2C_BUS
# undef CONFIG_SYS_MAX_I2C_BUS
# endif
#define CONFIG_SYS_MAX_I2C_BUS 1
#endif
/*
* The way speed is changed into duty often results in integer truncation
* with 50% duty, so we'll force rounding up to the next duty by adding 1
* to the max. In practice this will get us a speed of something like
* 385 KHz. The other limit is easy to handle as it is only 8 bits.
*/
#define I2C_SPEED_MAX 400000
#define I2C_SPEED_TO_DUTY(speed) (5000000 / (speed))
#define I2C_DUTY_MAX (I2C_SPEED_TO_DUTY(I2C_SPEED_MAX) + 1)
#define I2C_DUTY_MIN 0xff /* 8 bit limited */
#define SYS_I2C_DUTY I2C_SPEED_TO_DUTY(CONFIG_SYS_I2C_SPEED)
/* Note: duty is inverse of speed, so the comparisons below are correct */
#if SYS_I2C_DUTY < I2C_DUTY_MAX || SYS_I2C_DUTY > I2C_DUTY_MIN
# error "The I2C hardware can only operate 20KHz - 400KHz"
#endif
/* All transfers are described by this data structure */
struct adi_i2c_msg {
u8 flags;
#define I2C_M_COMBO 0x4
#define I2C_M_STOP 0x2
#define I2C_M_READ 0x1
int len; /* msg length */
u8 *buf; /* pointer to msg data */
int alen; /* addr length */
u8 *abuf; /* addr buffer */
};
/* Allow msec timeout per ~byte transfer */
#define I2C_TIMEOUT 10
/**
* wait_for_completion - manage the actual i2c transfer
* @msg: the i2c msg
*/
static int wait_for_completion(struct twi_regs *twi, struct adi_i2c_msg *msg)
{
u16 int_stat, ctl;
ulong timebase = get_timer(0);
do {
int_stat = readw(&twi->int_stat);
if (int_stat & XMTSERV) {
writew(XMTSERV, &twi->int_stat);
if (msg->alen) {
writew(*(msg->abuf++), &twi->xmt_data8);
--msg->alen;
} else if (!(msg->flags & I2C_M_COMBO) && msg->len) {
writew(*(msg->buf++), &twi->xmt_data8);
--msg->len;
} else {
ctl = readw(&twi->master_ctl);
if (msg->flags & I2C_M_COMBO)
writew(ctl | RSTART | MDIR,
&twi->master_ctl);
else
writew(ctl | STOP, &twi->master_ctl);
}
}
if (int_stat & RCVSERV) {
writew(RCVSERV, &twi->int_stat);
if (msg->len) {
*(msg->buf++) = readw(&twi->rcv_data8);
--msg->len;
} else if (msg->flags & I2C_M_STOP) {
ctl = readw(&twi->master_ctl);
writew(ctl | STOP, &twi->master_ctl);
}
}
if (int_stat & MERR) {
writew(MERR, &twi->int_stat);
return msg->len;
}
if (int_stat & MCOMP) {
writew(MCOMP, &twi->int_stat);
if (msg->flags & I2C_M_COMBO && msg->len) {
ctl = readw(&twi->master_ctl);
ctl = (ctl & ~RSTART) |
(min(msg->len, 0xff) << 6) | MEN | MDIR;
writew(ctl, &twi->master_ctl);
} else
break;
}
/* If we were able to do something, reset timeout */
if (int_stat)
timebase = get_timer(0);
} while (get_timer(timebase) < I2C_TIMEOUT);
return msg->len;
}
static int i2c_transfer(struct i2c_adapter *adap, uint8_t chip, uint addr,
int alen, uint8_t *buffer, int len, uint8_t flags)
{
struct twi_regs *twi = i2c_get_base(adap);
int ret;
u16 ctl;
uchar addr_buffer[] = {
(addr >> 0),
(addr >> 8),
(addr >> 16),
};
struct adi_i2c_msg msg = {
.flags = flags | (len >= 0xff ? I2C_M_STOP : 0),
.buf = buffer,
.len = len,
.abuf = addr_buffer,
.alen = alen,
};
/* wait for things to settle */
while (readw(&twi->master_stat) & BUSBUSY)
if (ctrlc())
return 1;
/* Set Transmit device address */
writew(chip, &twi->master_addr);
/* Clear the FIFO before starting things */
writew(XMTFLUSH | RCVFLUSH, &twi->fifo_ctl);
writew(0, &twi->fifo_ctl);
/* prime the pump */
if (msg.alen) {
len = (msg.flags & I2C_M_COMBO) ? msg.alen : msg.alen + len;
writew(*(msg.abuf++), &twi->xmt_data8);
--msg.alen;
} else if (!(msg.flags & I2C_M_READ) && msg.len) {
writew(*(msg.buf++), &twi->xmt_data8);
--msg.len;
}
/* clear int stat */
writew(-1, &twi->master_stat);
writew(-1, &twi->int_stat);
writew(0, &twi->int_mask);
/* Master enable */
ctl = readw(&twi->master_ctl);
ctl = (ctl & FAST) | (min(len, 0xff) << 6) | MEN |
((msg.flags & I2C_M_READ) ? MDIR : 0);
writew(ctl, &twi->master_ctl);
/* process the rest */
ret = wait_for_completion(twi, &msg);
if (ret) {
ctl = readw(&twi->master_ctl) & ~MEN;
writew(ctl, &twi->master_ctl);
ctl = readw(&twi->control) & ~TWI_ENA;
writew(ctl, &twi->control);
ctl = readw(&twi->control) | TWI_ENA;
writew(ctl, &twi->control);
}
return ret;
}
static uint adi_i2c_setspeed(struct i2c_adapter *adap, uint speed)
{
struct twi_regs *twi = i2c_get_base(adap);
u16 clkdiv = I2C_SPEED_TO_DUTY(speed);
/* Set TWI interface clock */
if (clkdiv < I2C_DUTY_MAX || clkdiv > I2C_DUTY_MIN)
return -1;
clkdiv = (clkdiv << 8) | (clkdiv & 0xff);
writew(clkdiv, &twi->clkdiv);
/* Don't turn it on */
writew(speed > 100000 ? FAST : 0, &twi->master_ctl);
return 0;
}
static void adi_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
struct twi_regs *twi = i2c_get_base(adap);
u16 prescale = ((get_i2c_clk() / 1000 / 1000 + 5) / 10) & 0x7F;
/* Set TWI internal clock as 10MHz */
writew(prescale, &twi->control);
/* Set TWI interface clock as specified */
i2c_set_bus_speed(speed);
/* Enable it */
writew(TWI_ENA | prescale, &twi->control);
}
static int adi_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer, int len)
{
return i2c_transfer(adap, chip, addr, alen, buffer,
len, alen ? I2C_M_COMBO : I2C_M_READ);
}
static int adi_i2c_write(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer, int len)
{
return i2c_transfer(adap, chip, addr, alen, buffer, len, 0);
}
static int adi_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
{
u8 byte;
return adi_i2c_read(adap, chip, 0, 0, &byte, 1);
}
static struct twi_regs *i2c_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if CONFIG_SYS_MAX_I2C_BUS > 2
case 2:
return (struct twi_regs *)TWI2_CLKDIV;
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 1
case 1:
return (struct twi_regs *)TWI1_CLKDIV;
#endif
case 0:
return (struct twi_regs *)TWI0_CLKDIV;
default:
printf("wrong hwadapnr: %d\n", adap->hwadapnr);
}
return NULL;
}
U_BOOT_I2C_ADAP_COMPLETE(adi_i2c0, adi_i2c_init, adi_i2c_probe,
adi_i2c_read, adi_i2c_write,
adi_i2c_setspeed,
CONFIG_SYS_I2C_SPEED,
0,
0)
#if CONFIG_SYS_MAX_I2C_BUS > 1
U_BOOT_I2C_ADAP_COMPLETE(adi_i2c1, adi_i2c_init, adi_i2c_probe,
adi_i2c_read, adi_i2c_write,
adi_i2c_setspeed,
CONFIG_SYS_I2C_SPEED,
0,
1)
#endif
#if CONFIG_SYS_MAX_I2C_BUS > 2
U_BOOT_I2C_ADAP_COMPLETE(adi_i2c2, adi_i2c_init, adi_i2c_probe,
adi_i2c_read, adi_i2c_write,
adi_i2c_setspeed,
CONFIG_SYS_I2C_SPEED,
0,
2)
#endif

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
#include <power/tps65090.h>
static int cros_ec_ldo_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_ldo_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
bool is_read = nmsgs > 1;
int fet_id, ret;
/*
* Look for reads and writes of the LDO registers. In either case the
* first message is a write with the register number as the first byte.
*/
if (!nmsgs || !msg->len || (msg->flags & I2C_M_RD)) {
debug("%s: Invalid message\n", __func__);
goto err;
}
fet_id = msg->buf[0] - REG_FET_BASE;
if (fet_id < 1 || fet_id > MAX_FET_NUM) {
debug("%s: Invalid FET %d\n", __func__, fet_id);
goto err;
}
if (is_read) {
uint8_t state;
ret = cros_ec_get_ldo(dev->parent, fet_id, &state);
if (!ret)
msg[1].buf[0] = state ?
FET_CTRL_ENFET | FET_CTRL_PGFET : 0;
} else {
bool on = msg->buf[1] & FET_CTRL_ENFET;
ret = cros_ec_set_ldo(dev->parent, fet_id, on);
}
return ret;
err:
/* Indicate that the message is unimplemented */
return -ENOSYS;
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_ldo_xfer,
.set_bus_speed = cros_ec_ldo_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-ldo-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_ldo) = {
.name = "cros_ec_ldo_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &cros_ec_i2c_ops,
};

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
static int cros_ec_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
return cros_ec_i2c_tunnel(dev->parent, msg, nmsgs);
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_i2c_xfer,
.set_bus_speed = cros_ec_i2c_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-i2c-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_tunnel) = {
.name = "cros_ec_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &cros_ec_i2c_ops,
};

View File

@@ -0,0 +1,384 @@
/*
* TI DaVinci (TMS320DM644x) I2C driver.
*
* (C) Copyright 2012-2014
* Texas Instruments Incorporated, <www.ti.com>
* (C) Copyright 2007 Sergey Kubushyn <ksi@koi8.net>
* --------------------------------------------------------
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <asm/arch/hardware.h>
#include <asm/arch/i2c_defs.h>
#include <asm/io.h>
#include "davinci_i2c.h"
#define CHECK_NACK() \
do {\
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
REG(&(i2c_base->i2c_con)) = 0;\
return 1;\
} \
} while (0)
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap);
static int wait_for_bus(struct i2c_adapter *adap)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
int stat, timeout;
REG(&(i2c_base->i2c_stat)) = 0xffff;
for (timeout = 0; timeout < 10; timeout++) {
stat = REG(&(i2c_base->i2c_stat));
if (!((stat) & I2C_STAT_BB)) {
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 0;
}
REG(&(i2c_base->i2c_stat)) = stat;
udelay(50000);
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return 1;
}
static int poll_i2c_irq(struct i2c_adapter *adap, int mask)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
int stat, timeout;
for (timeout = 0; timeout < 10; timeout++) {
udelay(1000);
stat = REG(&(i2c_base->i2c_stat));
if (stat & mask)
return stat;
}
REG(&(i2c_base->i2c_stat)) = 0xffff;
return stat | I2C_TIMEOUT;
}
static void flush_rx(struct i2c_adapter *adap)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
while (1) {
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_RRDY))
break;
REG(&(i2c_base->i2c_drr));
REG(&(i2c_base->i2c_stat)) = I2C_STAT_RRDY;
udelay(1000);
}
}
static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t div, psc;
psc = 2;
/* SCLL + SCLH */
div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;
REG(&(i2c_base->i2c_psc)) = psc; /* 27MHz / (2 + 1) = 9MHz */
REG(&(i2c_base->i2c_scll)) = (div * 50) / 100; /* 50% Duty */
REG(&(i2c_base->i2c_sclh)) = div - REG(&(i2c_base->i2c_scll));
adap->speed = speed;
return 0;
}
static void davinci_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
if (REG(&(i2c_base->i2c_con)) & I2C_CON_EN) {
REG(&(i2c_base->i2c_con)) = 0;
udelay(50000);
}
davinci_i2c_setspeed(adap, speed);
REG(&(i2c_base->i2c_oa)) = slaveadd;
REG(&(i2c_base->i2c_cnt)) = 0;
/* Interrupts must be enabled or I2C module won't work */
REG(&(i2c_base->i2c_ie)) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
/* Now enable I2C controller (get it out of reset) */
REG(&(i2c_base->i2c_con)) = I2C_CON_EN;
udelay(1000);
}
static int davinci_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
int rc = 1;
if (chip == REG(&(i2c_base->i2c_oa)))
return rc;
REG(&(i2c_base->i2c_con)) = 0;
if (wait_for_bus(adap))
return 1;
/* try to read one byte from current (or only) address */
REG(&(i2c_base->i2c_cnt)) = 1;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_STP);
udelay(50000);
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
rc = 0;
flush_rx(adap);
REG(&(i2c_base->i2c_stat)) = 0xffff;
} else {
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
udelay(20000);
if (wait_for_bus(adap))
return 1;
}
flush_rx(adap);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
return rc;
}
static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (wait_for_bus(adap))
return 1;
if (alen != 0) {
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
REG(&(i2c_base->i2c_cnt)) = alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
switch (alen) {
case 2:
/* Send address MSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
case 1:
/* Send address LSByte */
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY |
I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
if (!(tmp & I2C_STAT_ARDY)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
}
/* Address phase is over, now read 'len' bytes and stop */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
REG(&(i2c_base->i2c_cnt)) = len & 0xffff;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(adap, I2C_STAT_RRDY | I2C_STAT_NACK |
I2C_STAT_ROVR);
CHECK_NACK();
if (tmp & I2C_STAT_RRDY) {
buf[i] = REG(&(i2c_base->i2c_drr));
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
tmp = poll_i2c_irq(adap, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
flush_rx(adap);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
uint32_t addr, int alen, uint8_t *buf, int len)
{
struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t tmp;
int i;
if ((alen < 0) || (alen > 2)) {
printf("%s(): bogus address length %x\n", __func__, alen);
return 1;
}
if (len < 0) {
printf("%s(): bogus length %x\n", __func__, len);
return 1;
}
if (wait_for_bus(adap))
return 1;
/* Start address phase */
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_TRX | I2C_CON_STP;
REG(&(i2c_base->i2c_cnt)) = (alen == 0) ?
len & 0xffff : (len & 0xffff) + alen;
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
switch (alen) {
case 2:
/* Send address MSByte */
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = (addr >> 8) & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
/* No break, fall through */
case 1:
/* Send address LSByte */
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY) {
REG(&(i2c_base->i2c_dxr)) = addr & 0xff;
} else {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
}
for (i = 0; i < len; i++) {
tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
if (tmp & I2C_STAT_XRDY)
REG(&(i2c_base->i2c_dxr)) = buf[i];
else
return 1;
}
tmp = poll_i2c_irq(adap, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
if (!(tmp & I2C_STAT_SCD)) {
REG(&(i2c_base->i2c_con)) = 0;
return 1;
}
flush_rx(adap);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
return 0;
}
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if I2C_BUS_MAX >= 3
case 2:
return (struct i2c_regs *)I2C2_BASE;
#endif
#if I2C_BUS_MAX >= 2
case 1:
return (struct i2c_regs *)I2C1_BASE;
#endif
case 0:
return (struct i2c_regs *)I2C_BASE;
default:
printf("wrong hwadapnr: %d\n", adap->hwadapnr);
}
return NULL;
}
U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED,
CONFIG_SYS_DAVINCI_I2C_SLAVE,
0)
#if I2C_BUS_MAX >= 2
U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED1,
CONFIG_SYS_DAVINCI_I2C_SLAVE1,
1)
#endif
#if I2C_BUS_MAX >= 3
U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED2,
CONFIG_SYS_DAVINCI_I2C_SLAVE2,
2)
#endif

View File

@@ -0,0 +1,78 @@
/*
* (C) Copyright 2004-2014
* Texas Instruments, <www.ti.com>
*
* Some changes copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _DAVINCI_I2C_H_
#define _DAVINCI_I2C_H_
#define I2C_WRITE 0
#define I2C_READ 1
struct i2c_regs {
u32 i2c_oa;
u32 i2c_ie;
u32 i2c_stat;
u32 i2c_scll;
u32 i2c_sclh;
u32 i2c_cnt;
u32 i2c_drr;
u32 i2c_sa;
u32 i2c_dxr;
u32 i2c_con;
u32 i2c_iv;
u32 res_2c;
u32 i2c_psc;
};
/* I2C masks */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_SCD_IE (1 << 5) /* Stop condition detect interrupt enable */
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_SCD (1 << 5) /* Stop condition detect */
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Code Register (I2C_INTCODE): */
#define I2C_INTCODE_MASK 7
#define I2C_INTCODE_NONE 0
#define I2C_INTCODE_AL 1 /* Arbitration lost */
#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
#define I2C_INTCODE_ARDY 3 /* Register access ready */
#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
#define I2C_INTCODE_SCD 6 /* Stop condition detect */
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 5) /* I2C module enable */
#define I2C_CON_STB (1 << 4) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Tx/Rx mode (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 11) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 13) /* Start condition (master mode only) */
#define I2C_CON_FREE (1 << 14) /* Free run on emulation */
#define I2C_TIMEOUT 0xffff0000 /* Timeout mask for poll_i2c_irq() */
#endif

View File

@@ -0,0 +1,605 @@
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <pci.h>
#include <asm/io.h>
#include "designware_i2c.h"
struct dw_scl_sda_cfg {
u32 ss_hcnt;
u32 fs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
u32 sda_hold;
};
#ifdef CONFIG_X86
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
.fs_hcnt = 0x55,
.ss_lcnt = 0x200,
.fs_lcnt = 0x99,
.sda_hold = 0x6,
};
#endif
struct dw_i2c {
struct i2c_regs *regs;
struct dw_scl_sda_cfg *scl_sda_cfg;
};
#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
u32 ena = enable ? IC_ENABLE_0B : 0;
writel(ena, &i2c_base->ic_enable);
}
#else
static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
{
u32 ena = enable ? IC_ENABLE_0B : 0;
int timeout = 100;
do {
writel(ena, &i2c_base->ic_enable);
if ((readl(&i2c_base->ic_enable_status) & IC_ENABLE_0B) == ena)
return;
/*
* Wait 10 times the signaling period of the highest I2C
* transfer supported by the driver (for 400KHz this is
* 25us) as described in the DesignWare I2C databook.
*/
udelay(25);
} while (timeout--);
printf("timeout in %sabling I2C adapter\n", enable ? "en" : "dis");
}
#endif
/*
* i2c_set_bus_speed - Set the i2c speed
* @speed: required i2c speed
*
* Set the i2c speed.
*/
static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
struct dw_scl_sda_cfg *scl_sda_cfg,
unsigned int speed)
{
unsigned int cntl;
unsigned int hcnt, lcnt;
int i2c_spd;
if (speed >= I2C_MAX_SPEED)
i2c_spd = IC_SPEED_MODE_MAX;
else if (speed >= I2C_FAST_SPEED)
i2c_spd = IC_SPEED_MODE_FAST;
else
i2c_spd = IC_SPEED_MODE_STANDARD;
/* to set speed cltr must be disabled */
dw_i2c_enable(i2c_base, false);
cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
switch (i2c_spd) {
#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
case IC_SPEED_MODE_MAX:
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
break;
#endif
case IC_SPEED_MODE_STANDARD:
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->ss_hcnt;
lcnt = scl_sda_cfg->ss_lcnt;
} else {
hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_ss_scl_hcnt);
writel(lcnt, &i2c_base->ic_ss_scl_lcnt);
break;
case IC_SPEED_MODE_FAST:
default:
cntl |= IC_CON_SPD_FS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
}
writel(hcnt, &i2c_base->ic_fs_scl_hcnt);
writel(lcnt, &i2c_base->ic_fs_scl_lcnt);
break;
}
writel(cntl, &i2c_base->ic_con);
/* Configure SDA Hold Time if required */
if (scl_sda_cfg)
writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold);
/* Enable back i2c now speed set */
dw_i2c_enable(i2c_base, true);
return 0;
}
/*
* i2c_setaddress - Sets the target slave address
* @i2c_addr: target i2c address
*
* Sets the target slave address.
*/
static void i2c_setaddress(struct i2c_regs *i2c_base, unsigned int i2c_addr)
{
/* Disable i2c */
dw_i2c_enable(i2c_base, false);
writel(i2c_addr, &i2c_base->ic_tar);
/* Enable i2c */
dw_i2c_enable(i2c_base, true);
}
/*
* i2c_flush_rxfifo - Flushes the i2c RX FIFO
*
* Flushes the i2c RX FIFO
*/
static void i2c_flush_rxfifo(struct i2c_regs *i2c_base)
{
while (readl(&i2c_base->ic_status) & IC_STATUS_RFNE)
readl(&i2c_base->ic_cmd_data);
}
/*
* i2c_wait_for_bb - Waits for bus busy
*
* Waits for bus busy
*/
static int i2c_wait_for_bb(struct i2c_regs *i2c_base)
{
unsigned long start_time_bb = get_timer(0);
while ((readl(&i2c_base->ic_status) & IC_STATUS_MA) ||
!(readl(&i2c_base->ic_status) & IC_STATUS_TFE)) {
/* Evaluate timeout */
if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB))
return 1;
}
return 0;
}
static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr,
int alen)
{
if (i2c_wait_for_bb(i2c_base))
return 1;
i2c_setaddress(i2c_base, chip);
while (alen) {
alen--;
/* high byte address going out first */
writel((addr >> (alen * 8)) & 0xff,
&i2c_base->ic_cmd_data);
}
return 0;
}
static int i2c_xfer_finish(struct i2c_regs *i2c_base)
{
ulong start_stop_det = get_timer(0);
while (1) {
if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) {
readl(&i2c_base->ic_clr_stop_det);
break;
} else if (get_timer(start_stop_det) > I2C_STOPDET_TO) {
break;
}
}
if (i2c_wait_for_bb(i2c_base)) {
printf("Timed out waiting for bus\n");
return 1;
}
i2c_flush_rxfifo(i2c_base);
return 0;
}
/*
* i2c_read - Read from i2c memory
* @chip: target i2c address
* @addr: address to read from
* @alen:
* @buffer: buffer for read data
* @len: no of bytes to be read
*
* Read from i2c memory.
*/
static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
unsigned long start_time_rx;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
addr);
#endif
if (i2c_xfer_init(i2c_base, dev, addr, alen))
return 1;
start_time_rx = get_timer(0);
while (len) {
if (len == 1)
writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data);
else
writel(IC_CMD, &i2c_base->ic_cmd_data);
if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) {
*buffer++ = (uchar)readl(&i2c_base->ic_cmd_data);
len--;
start_time_rx = get_timer(0);
} else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
return 1;
}
}
return i2c_xfer_finish(i2c_base);
}
/*
* i2c_write - Write to i2c memory
* @chip: target i2c address
* @addr: address to read from
* @alen:
* @buffer: buffer for read data
* @len: no of bytes to be read
*
* Write to i2c memory.
*/
static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
int nb = len;
unsigned long start_time_tx;
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8));
debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev,
addr);
#endif
if (i2c_xfer_init(i2c_base, dev, addr, alen))
return 1;
start_time_tx = get_timer(0);
while (len) {
if (readl(&i2c_base->ic_status) & IC_STATUS_TFNF) {
if (--len == 0) {
writel(*buffer | IC_STOP,
&i2c_base->ic_cmd_data);
} else {
writel(*buffer, &i2c_base->ic_cmd_data);
}
buffer++;
start_time_tx = get_timer(0);
} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
printf("Timed out. i2c write Failed\n");
return 1;
}
}
return i2c_xfer_finish(i2c_base);
}
/*
* __dw_i2c_init - Init function
* @speed: required i2c speed
* @slaveaddr: slave address for the device
*
* Initialization function.
*/
static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr)
{
/* Disable i2c */
dw_i2c_enable(i2c_base, false);
writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_base->ic_con);
writel(IC_RX_TL, &i2c_base->ic_rx_tl);
writel(IC_TX_TL, &i2c_base->ic_tx_tl);
writel(IC_STOP_DET, &i2c_base->ic_intr_mask);
#ifndef CONFIG_DM_I2C
__dw_i2c_set_bus_speed(i2c_base, NULL, speed);
writel(slaveaddr, &i2c_base->ic_sar);
#endif
/* Enable i2c */
dw_i2c_enable(i2c_base, true);
}
#ifndef CONFIG_DM_I2C
/*
* The legacy I2C functions. These need to get removed once
* all users of this driver are converted to DM.
*/
static struct i2c_regs *i2c_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#if CONFIG_SYS_I2C_BUS_MAX >= 4
case 3:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE3;
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 3
case 2:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE2;
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 2
case 1:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE1;
#endif
case 0:
return (struct i2c_regs *)CONFIG_SYS_I2C_BASE;
default:
printf("Wrong I2C-adapter number %d\n", adap->hwadapnr);
}
return NULL;
}
static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
adap->speed = speed;
return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed);
}
static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
__dw_i2c_init(i2c_get_base(adap), speed, slaveaddr);
}
static int dw_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
return __dw_i2c_read(i2c_get_base(adap), dev, addr, alen, buffer, len);
}
static int dw_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *buffer, int len)
{
return __dw_i2c_write(i2c_get_base(adap), dev, addr, alen, buffer, len);
}
/* dw_i2c_probe - Probe the i2c chip */
static int dw_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
struct i2c_regs *i2c_base = i2c_get_base(adap);
u32 tmp;
int ret;
/*
* Try to read the first location of the chip.
*/
ret = __dw_i2c_read(i2c_base, dev, 0, 1, (uchar *)&tmp, 1);
if (ret)
dw_i2c_init(adap, adap->speed, adap->slaveaddr);
return ret;
}
U_BOOT_I2C_ADAP_COMPLETE(dw_0, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
#if CONFIG_SYS_I2C_BUS_MAX >= 2
U_BOOT_I2C_ADAP_COMPLETE(dw_1, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED1, CONFIG_SYS_I2C_SLAVE1, 1)
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 3
U_BOOT_I2C_ADAP_COMPLETE(dw_2, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED2, CONFIG_SYS_I2C_SLAVE2, 2)
#endif
#if CONFIG_SYS_I2C_BUS_MAX >= 4
U_BOOT_I2C_ADAP_COMPLETE(dw_3, dw_i2c_init, dw_i2c_probe, dw_i2c_read,
dw_i2c_write, dw_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED3, CONFIG_SYS_I2C_SLAVE3, 3)
#endif
#else /* CONFIG_DM_I2C */
/* The DM I2C functions */
static int designware_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct dw_i2c *i2c = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = __dw_i2c_read(i2c->regs, msg->addr, 0, 0,
msg->buf, msg->len);
} else {
ret = __dw_i2c_write(i2c->regs, msg->addr, 0, 0,
msg->buf, msg->len);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dw_i2c *i2c = dev_get_priv(bus);
return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed);
}
static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct dw_i2c *i2c = dev_get_priv(bus);
struct i2c_regs *i2c_base = i2c->regs;
u32 tmp;
int ret;
/* Try to read the first location of the chip */
ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1);
if (ret)
__dw_i2c_init(i2c_base, 0, 0);
return ret;
}
static int designware_i2c_probe(struct udevice *bus)
{
struct dw_i2c *priv = dev_get_priv(bus);
if (device_is_on_pci_bus(bus)) {
#ifdef CONFIG_DM_PCI
/* Save base address from PCI BAR */
priv->regs = (struct i2c_regs *)
dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
#ifdef CONFIG_X86
/* Use BayTrail specific timing values */
priv->scl_sda_cfg = &byt_config;
#endif
#endif
} else {
priv->regs = (struct i2c_regs *)dev_get_addr_ptr(bus);
}
__dw_i2c_init(priv->regs, 0, 0);
return 0;
}
static int designware_i2c_bind(struct udevice *dev)
{
static int num_cards;
char name[20];
/* Create a unique device name for PCI type devices */
if (device_is_on_pci_bus(dev)) {
/*
* ToDo:
* Setting req_seq in the driver is probably not recommended.
* But without a DT alias the number is not configured. And
* using this driver is impossible for PCIe I2C devices.
* This can be removed, once a better (correct) way for this
* is found and implemented.
*/
dev->req_seq = num_cards;
sprintf(name, "i2c_designware#%u", num_cards++);
device_set_name(dev, name);
}
return 0;
}
static const struct dm_i2c_ops designware_i2c_ops = {
.xfer = designware_i2c_xfer,
.probe_chip = designware_i2c_probe_chip,
.set_bus_speed = designware_i2c_set_bus_speed,
};
static const struct udevice_id designware_i2c_ids[] = {
{ .compatible = "snps,designware-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_designware) = {
.name = "i2c_designware",
.id = UCLASS_I2C,
.of_match = designware_i2c_ids,
.bind = designware_i2c_bind,
.probe = designware_i2c_probe,
.priv_auto_alloc_size = sizeof(struct dw_i2c),
.ops = &designware_i2c_ops,
};
#ifdef CONFIG_X86
static struct pci_device_id designware_pci_supported[] = {
/* Intel BayTrail has 7 I2C controller located on the PCI bus */
{ PCI_VDEVICE(INTEL, 0x0f41) },
{ PCI_VDEVICE(INTEL, 0x0f42) },
{ PCI_VDEVICE(INTEL, 0x0f43) },
{ PCI_VDEVICE(INTEL, 0x0f44) },
{ PCI_VDEVICE(INTEL, 0x0f45) },
{ PCI_VDEVICE(INTEL, 0x0f46) },
{ PCI_VDEVICE(INTEL, 0x0f47) },
{},
};
U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
#endif
#endif /* CONFIG_DM_I2C */

View File

@@ -0,0 +1,135 @@
/*
* (C) Copyright 2009
* Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __DW_I2C_H_
#define __DW_I2C_H_
struct i2c_regs {
u32 ic_con; /* 0x00 */
u32 ic_tar; /* 0x04 */
u32 ic_sar; /* 0x08 */
u32 ic_hs_maddr; /* 0x0c */
u32 ic_cmd_data; /* 0x10 */
u32 ic_ss_scl_hcnt; /* 0x14 */
u32 ic_ss_scl_lcnt; /* 0x18 */
u32 ic_fs_scl_hcnt; /* 0x1c */
u32 ic_fs_scl_lcnt; /* 0x20 */
u32 ic_hs_scl_hcnt; /* 0x24 */
u32 ic_hs_scl_lcnt; /* 0x28 */
u32 ic_intr_stat; /* 0x2c */
u32 ic_intr_mask; /* 0x30 */
u32 ic_raw_intr_stat; /* 0x34 */
u32 ic_rx_tl; /* 0x38 */
u32 ic_tx_tl; /* 0x3c */
u32 ic_clr_intr; /* 0x40 */
u32 ic_clr_rx_under; /* 0x44 */
u32 ic_clr_rx_over; /* 0x48 */
u32 ic_clr_tx_over; /* 0x4c */
u32 ic_clr_rd_req; /* 0x50 */
u32 ic_clr_tx_abrt; /* 0x54 */
u32 ic_clr_rx_done; /* 0x58 */
u32 ic_clr_activity; /* 0x5c */
u32 ic_clr_stop_det; /* 0x60 */
u32 ic_clr_start_det; /* 0x64 */
u32 ic_clr_gen_call; /* 0x68 */
u32 ic_enable; /* 0x6c */
u32 ic_status; /* 0x70 */
u32 ic_txflr; /* 0x74 */
u32 ic_rxflr; /* 0x78 */
u32 ic_sda_hold; /* 0x7c */
u32 ic_tx_abrt_source; /* 0x80 */
u8 res1[0x18]; /* 0x84 */
u32 ic_enable_status; /* 0x9c */
};
#if !defined(IC_CLK)
#define IC_CLK 166
#endif
#define NANO_TO_MICRO 1000
/* High and low times in different speed modes (in ns) */
#define MIN_SS_SCL_HIGHTIME 4000
#define MIN_SS_SCL_LOWTIME 4700
#define MIN_FS_SCL_HIGHTIME 600
#define MIN_FS_SCL_LOWTIME 1300
#define MIN_HS_SCL_HIGHTIME 60
#define MIN_HS_SCL_LOWTIME 160
/* Worst case timeout for 1 byte is kept as 2ms */
#define I2C_BYTE_TO (CONFIG_SYS_HZ/500)
#define I2C_STOPDET_TO (CONFIG_SYS_HZ/500)
#define I2C_BYTE_TO_BB (I2C_BYTE_TO * 16)
/* i2c control register definitions */
#define IC_CON_SD 0x0040
#define IC_CON_RE 0x0020
#define IC_CON_10BITADDRMASTER 0x0010
#define IC_CON_10BITADDR_SLAVE 0x0008
#define IC_CON_SPD_MSK 0x0006
#define IC_CON_SPD_SS 0x0002
#define IC_CON_SPD_FS 0x0004
#define IC_CON_SPD_HS 0x0006
#define IC_CON_MM 0x0001
/* i2c target address register definitions */
#define TAR_ADDR 0x0050
/* i2c slave address register definitions */
#define IC_SLAVE_ADDR 0x0002
/* i2c data buffer and command register definitions */
#define IC_CMD 0x0100
#define IC_STOP 0x0200
/* i2c interrupt status register definitions */
#define IC_GEN_CALL 0x0800
#define IC_START_DET 0x0400
#define IC_STOP_DET 0x0200
#define IC_ACTIVITY 0x0100
#define IC_RX_DONE 0x0080
#define IC_TX_ABRT 0x0040
#define IC_RD_REQ 0x0020
#define IC_TX_EMPTY 0x0010
#define IC_TX_OVER 0x0008
#define IC_RX_FULL 0x0004
#define IC_RX_OVER 0x0002
#define IC_RX_UNDER 0x0001
/* fifo threshold register definitions */
#define IC_TL0 0x00
#define IC_TL1 0x01
#define IC_TL2 0x02
#define IC_TL3 0x03
#define IC_TL4 0x04
#define IC_TL5 0x05
#define IC_TL6 0x06
#define IC_TL7 0x07
#define IC_RX_TL IC_TL0
#define IC_TX_TL IC_TL0
/* i2c enable register definitions */
#define IC_ENABLE_0B 0x0001
/* i2c status register definitions */
#define IC_STATUS_SA 0x0040
#define IC_STATUS_MA 0x0020
#define IC_STATUS_RFF 0x0010
#define IC_STATUS_RFNE 0x0008
#define IC_STATUS_TFE 0x0004
#define IC_STATUS_TFNF 0x0002
#define IC_STATUS_ACT 0x0001
/* Speed Selection */
#define IC_SPEED_MODE_STANDARD 1
#define IC_SPEED_MODE_FAST 2
#define IC_SPEED_MODE_MAX 3
#define I2C_MAX_SPEED 3400000
#define I2C_FAST_SPEED 400000
#define I2C_STANDARD_SPEED 100000
#endif /* __DW_I2C_H_ */

View File

@@ -0,0 +1,664 @@
/*
* Copyright 2006,2009 Freescale Semiconductor, Inc.
*
* 2012, Heiko Schocher, DENX Software Engineering, hs@denx.de.
* Changes for multibus/multiadapter I2C support.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <command.h>
#include <i2c.h> /* Functional interface */
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
#include <dm.h>
#include <mapmem.h>
/* The maximum number of microseconds we will wait until another master has
* released the bus. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_MBB_TIMEOUT
#define CONFIG_I2C_MBB_TIMEOUT 100000
#endif
/* The maximum number of microseconds we will wait for a read or write
* operation to complete. If not defined in the board header file, then use a
* generic value.
*/
#ifndef CONFIG_I2C_TIMEOUT
#define CONFIG_I2C_TIMEOUT 100000
#endif
#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_DM_I2C
static const struct fsl_i2c_base *i2c_base[4] = {
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET),
#endif
#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C3_OFFSET),
#endif
#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C4_OFFSET)
#endif
};
#endif
/* I2C speed map for a DFSR value of 1 */
/*
* Map I2C frequency dividers to FDR and DFSR values
*
* This structure is used to define the elements of a table that maps I2C
* frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
* programmed into the Frequency Divider Ratio (FDR) and Digital Filter
* Sampling Rate (DFSR) registers.
*
* The actual table should be defined in the board file, and it must be called
* fsl_i2c_speed_map[].
*
* The last entry of the table must have a value of {-1, X}, where X is same
* FDR/DFSR values as the second-to-last entry. This guarantees that any
* search through the array will always find a match.
*
* The values of the divider must be in increasing numerical order, i.e.
* fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
*
* For this table, the values are based on a value of 1 for the DFSR
* register. See the application note AN2919 "Determining the I2C Frequency
* Divider Ratio for SCL"
*
* ColdFire I2C frequency dividers for FDR values are different from
* PowerPC. The protocol to use the I2C module is still the same.
* A different table is defined and are based on MCF5xxx user manual.
*
*/
static const struct {
unsigned short divider;
u8 fdr;
} fsl_i2c_speed_map[] = {
#ifdef __M68K__
{20, 32}, {22, 33}, {24, 34}, {26, 35},
{28, 0}, {28, 36}, {30, 1}, {32, 37},
{34, 2}, {36, 38}, {40, 3}, {40, 39},
{44, 4}, {48, 5}, {48, 40}, {56, 6},
{56, 41}, {64, 42}, {68, 7}, {72, 43},
{80, 8}, {80, 44}, {88, 9}, {96, 41},
{104, 10}, {112, 42}, {128, 11}, {128, 43},
{144, 12}, {160, 13}, {160, 48}, {192, 14},
{192, 49}, {224, 50}, {240, 15}, {256, 51},
{288, 16}, {320, 17}, {320, 52}, {384, 18},
{384, 53}, {448, 54}, {480, 19}, {512, 55},
{576, 20}, {640, 21}, {640, 56}, {768, 22},
{768, 57}, {960, 23}, {896, 58}, {1024, 59},
{1152, 24}, {1280, 25}, {1280, 60}, {1536, 26},
{1536, 61}, {1792, 62}, {1920, 27}, {2048, 63},
{2304, 28}, {2560, 29}, {3072, 30}, {3840, 31},
{-1, 31}
#endif
};
/**
* Set the I2C bus speed for a given I2C device
*
* @param base: the I2C device registers
* @i2c_clk: I2C bus clock frequency
* @speed: the desired speed of the bus
*
* The I2C device must be stopped before calling this function.
*
* The return value is the actual bus speed that is set.
*/
static unsigned int set_i2c_bus_speed(const struct fsl_i2c_base *base,
unsigned int i2c_clk, unsigned int speed)
{
unsigned short divider = min(i2c_clk / speed, (unsigned int)USHRT_MAX);
/*
* We want to choose an FDR/DFSR that generates an I2C bus speed that
* is equal to or lower than the requested speed. That means that we
* want the first divider that is equal to or greater than the
* calculated divider.
*/
#ifdef __PPC__
u8 dfsr, fdr = 0x31; /* Default if no FDR found */
/* a, b and dfsr matches identifiers A,B and C respectively in AN2919 */
unsigned short a, b, ga, gb;
unsigned long c_div, est_div;
#ifdef CONFIG_FSL_I2C_CUSTOM_DFSR
dfsr = CONFIG_FSL_I2C_CUSTOM_DFSR;
#else
/* Condition 1: dfsr <= 50/T */
dfsr = (5 * (i2c_clk / 1000)) / 100000;
#endif
#ifdef CONFIG_FSL_I2C_CUSTOM_FDR
fdr = CONFIG_FSL_I2C_CUSTOM_FDR;
speed = i2c_clk / divider; /* Fake something */
#else
debug("Requested speed:%d, i2c_clk:%d\n", speed, i2c_clk);
if (!dfsr)
dfsr = 1;
est_div = ~0;
for (ga = 0x4, a = 10; a <= 30; ga++, a += 2) {
for (gb = 0; gb < 8; gb++) {
b = 16 << gb;
c_div = b * (a + ((3*dfsr)/b)*2);
if ((c_div > divider) && (c_div < est_div)) {
unsigned short bin_gb, bin_ga;
est_div = c_div;
bin_gb = gb << 2;
bin_ga = (ga & 0x3) | ((ga & 0x4) << 3);
fdr = bin_gb | bin_ga;
speed = i2c_clk / est_div;
debug("FDR:0x%.2x, div:%ld, ga:0x%x, gb:0x%x, "
"a:%d, b:%d, speed:%d\n",
fdr, est_div, ga, gb, a, b, speed);
/* Condition 2 not accounted for */
debug("Tr <= %d ns\n",
(b - 3 * dfsr) * 1000000 /
(i2c_clk / 1000));
}
}
if (a == 20)
a += 2;
if (a == 24)
a += 4;
}
debug("divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
debug("FDR:0x%.2x, speed:%d\n", fdr, speed);
#endif
writeb(dfsr, &base->dfsrr); /* set default filter */
writeb(fdr, &base->fdr); /* set bus speed */
#else
unsigned int i;
for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++)
if (fsl_i2c_speed_map[i].divider >= divider) {
u8 fdr;
fdr = fsl_i2c_speed_map[i].fdr;
speed = i2c_clk / fsl_i2c_speed_map[i].divider;
writeb(fdr, &base->fdr); /* set bus speed */
break;
}
#endif
return speed;
}
#ifndef CONFIG_DM_I2C
static unsigned int get_i2c_clock(int bus)
{
if (bus)
return gd->arch.i2c2_clk; /* I2C2 clock */
else
return gd->arch.i2c1_clk; /* I2C1 clock */
}
#endif
static int fsl_i2c_fixup(const struct fsl_i2c_base *base)
{
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
unsigned long long timeval = 0;
int ret = -1;
unsigned int flags = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_I2C_A004447
unsigned int svr = get_svr();
if ((SVR_SOC_VER(svr) == SVR_8548 && IS_SVR_REV(svr, 3, 1)) ||
(SVR_REV(svr) <= CONFIG_SYS_FSL_A004447_SVR_REV))
flags = I2C_CR_BIT6;
#endif
writeb(I2C_CR_MEN | I2C_CR_MSTA, &base->cr);
timeval = get_ticks();
while (!(readb(&base->sr) & I2C_SR_MBB)) {
if ((get_ticks() - timeval) > timeout)
goto err;
}
if (readb(&base->sr) & I2C_SR_MAL) {
/* SDA is stuck low */
writeb(0, &base->cr);
udelay(100);
writeb(I2C_CR_MSTA | flags, &base->cr);
writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &base->cr);
}
readb(&base->dr);
timeval = get_ticks();
while (!(readb(&base->sr) & I2C_SR_MIF)) {
if ((get_ticks() - timeval) > timeout)
goto err;
}
ret = 0;
err:
writeb(I2C_CR_MEN | flags, &base->cr);
writeb(0, &base->sr);
udelay(100);
return ret;
}
static void __i2c_init(const struct fsl_i2c_base *base, int speed, int
slaveadd, int i2c_clk, int busnum)
{
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
unsigned long long timeval;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
writeb(0, &base->cr); /* stop I2C controller */
udelay(5); /* let it shutdown in peace */
set_i2c_bus_speed(base, i2c_clk, speed);
writeb(slaveadd << 1, &base->adr);/* write slave address */
writeb(0x0, &base->sr); /* clear status register */
writeb(I2C_CR_MEN, &base->cr); /* start I2C controller */
timeval = get_ticks();
while (readb(&base->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) < timeout)
continue;
if (fsl_i2c_fixup(base))
debug("i2c_init: BUS#%d failed to init\n",
busnum);
break;
}
#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
/* Call board specific i2c bus reset routine AFTER the bus has been
* initialized. Use either this callpoint or i2c_init_board;
* which is called before i2c_init operations.
* For details about this problem see doc/I2C_Edge_Conditions.
*/
i2c_board_late_init();
#endif
}
static int
i2c_wait4bus(const struct fsl_i2c_base *base)
{
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
while (readb(&base->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) > timeout)
return -1;
}
return 0;
}
static inline int
i2c_wait(const struct fsl_i2c_base *base, int write)
{
u32 csr;
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
do {
csr = readb(&base->sr);
if (!(csr & I2C_SR_MIF))
continue;
/* Read again to allow register to stabilise */
csr = readb(&base->sr);
writeb(0x0, &base->sr);
if (csr & I2C_SR_MAL) {
debug("i2c_wait: MAL\n");
return -1;
}
if (!(csr & I2C_SR_MCF)) {
debug("i2c_wait: unfinished\n");
return -1;
}
if (write == I2C_WRITE_BIT && (csr & I2C_SR_RXAK)) {
debug("i2c_wait: No RXACK\n");
return -1;
}
return 0;
} while ((get_ticks() - timeval) < timeout);
debug("i2c_wait: timed out\n");
return -1;
}
static inline int
i2c_write_addr(const struct fsl_i2c_base *base, u8 dev, u8 dir, int rsta)
{
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
| (rsta ? I2C_CR_RSTA : 0),
&base->cr);
writeb((dev << 1) | dir, &base->dr);
if (i2c_wait(base, I2C_WRITE_BIT) < 0)
return 0;
return 1;
}
static inline int
__i2c_write_data(const struct fsl_i2c_base *base, u8 *data, int length)
{
int i;
for (i = 0; i < length; i++) {
writeb(data[i], &base->dr);
if (i2c_wait(base, I2C_WRITE_BIT) < 0)
break;
}
return i;
}
static inline int
__i2c_read_data(const struct fsl_i2c_base *base, u8 *data, int length)
{
int i;
writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
&base->cr);
/* dummy read */
readb(&base->dr);
for (i = 0; i < length; i++) {
if (i2c_wait(base, I2C_READ_BIT) < 0)
break;
/* Generate ack on last next to last byte */
if (i == length - 2)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
&base->cr);
/* Do not generate stop on last byte */
if (i == length - 1)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
&base->cr);
data[i] = readb(&base->dr);
}
return i;
}
static int
__i2c_read(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset, int olen,
u8 *data, int dlen)
{
int ret = -1; /* signal error */
if (i2c_wait4bus(base) < 0)
return -1;
/* Some drivers use offset lengths in excess of 4 bytes. These drivers
* adhere to the following convention:
* - the offset length is passed as negative (that is, the absolute
* value of olen is the actual offset length)
* - the offset itself is passed in data, which is overwritten by the
* subsequent read operation
*/
if (olen < 0) {
if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0)
ret = __i2c_write_data(base, data, -olen);
if (ret != -olen)
return -1;
if (dlen && i2c_write_addr(base, chip_addr,
I2C_READ_BIT, 1) != 0)
ret = __i2c_read_data(base, data, dlen);
} else {
if ((!dlen || olen > 0) &&
i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
__i2c_write_data(base, offset, olen) == olen)
ret = 0; /* No error so far */
if (dlen && i2c_write_addr(base, chip_addr, I2C_READ_BIT,
olen ? 1 : 0) != 0)
ret = __i2c_read_data(base, data, dlen);
}
writeb(I2C_CR_MEN, &base->cr);
if (i2c_wait4bus(base)) /* Wait until STOP */
debug("i2c_read: wait4bus timed out\n");
if (ret == dlen)
return 0;
return -1;
}
static int
__i2c_write(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset, int olen,
u8 *data, int dlen)
{
int ret = -1; /* signal error */
if (i2c_wait4bus(base) < 0)
return -1;
if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
__i2c_write_data(base, offset, olen) == olen) {
ret = __i2c_write_data(base, data, dlen);
}
writeb(I2C_CR_MEN, &base->cr);
if (i2c_wait4bus(base)) /* Wait until STOP */
debug("i2c_write: wait4bus timed out\n");
if (ret == dlen)
return 0;
return -1;
}
static int
__i2c_probe_chip(const struct fsl_i2c_base *base, uchar chip)
{
/* For unknow reason the controller will ACK when
* probing for a slave with the same address, so skip
* it.
*/
if (chip == (readb(&base->adr) >> 1))
return -1;
return __i2c_read(base, chip, 0, 0, NULL, 0);
}
static unsigned int __i2c_set_bus_speed(const struct fsl_i2c_base *base,
unsigned int speed, int i2c_clk)
{
writeb(0, &base->cr); /* stop controller */
set_i2c_bus_speed(base, i2c_clk, speed);
writeb(I2C_CR_MEN, &base->cr); /* start controller */
return 0;
}
#ifndef CONFIG_DM_I2C
static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
__i2c_init(i2c_base[adap->hwadapnr], speed, slaveadd,
get_i2c_clock(adap->hwadapnr), adap->hwadapnr);
}
static int
fsl_i2c_probe_chip(struct i2c_adapter *adap, uchar chip)
{
return __i2c_probe_chip(i2c_base[adap->hwadapnr], chip);
}
static int
fsl_i2c_read(struct i2c_adapter *adap, u8 chip_addr, uint offset, int olen,
u8 *data, int dlen)
{
u8 *o = (u8 *)&offset;
return __i2c_read(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
olen, data, dlen);
}
static int
fsl_i2c_write(struct i2c_adapter *adap, u8 chip_addr, uint offset, int olen,
u8 *data, int dlen)
{
u8 *o = (u8 *)&offset;
return __i2c_write(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
olen, data, dlen);
}
static unsigned int fsl_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
return __i2c_set_bus_speed(i2c_base[adap->hwadapnr], speed,
get_i2c_clock(adap->hwadapnr));
}
/*
* Register fsl i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
0)
#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
1)
#endif
#ifdef CONFIG_SYS_FSL_I2C3_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_2, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C3_SPEED, CONFIG_SYS_FSL_I2C3_SLAVE,
2)
#endif
#ifdef CONFIG_SYS_FSL_I2C4_OFFSET
U_BOOT_I2C_ADAP_COMPLETE(fsl_3, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
fsl_i2c_write, fsl_i2c_set_bus_speed,
CONFIG_SYS_FSL_I2C4_SPEED, CONFIG_SYS_FSL_I2C4_SLAVE,
3)
#endif
#else /* CONFIG_DM_I2C */
static int fsl_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
return __i2c_probe_chip(dev->base, chip_addr);
}
static int fsl_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
return __i2c_set_bus_speed(dev->base, speed, dev->i2c_clk);
}
static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
u64 reg;
u32 addr, size;
reg = fdtdec_get_addr(gd->fdt_blob, bus->of_offset, "reg");
addr = reg >> 32;
size = reg & 0xFFFFFFFF;
dev->base = map_sysmem(CONFIG_SYS_IMMR + addr, size);
if (!dev->base)
return -ENOMEM;
dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"cell-index", -1);
dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"u-boot,i2c-slave-addr", 0x7f);
dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"clock-frequency", 400000);
dev->i2c_clk = dev->index ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
return 0;
}
static int fsl_i2c_probe(struct udevice *bus)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
__i2c_init(dev->base, dev->speed, dev->slaveadd, dev->i2c_clk,
dev->index);
return 0;
}
static int fsl_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct fsl_i2c_dev *dev = dev_get_priv(bus);
struct i2c_msg *dmsg, *omsg, dummy;
memset(&dummy, 0, sizeof(struct i2c_msg));
/* We expect either two messages (one with an offset and one with the
* actucal data) or one message (just data) */
if (nmsgs > 2 || nmsgs == 0) {
debug("%s: Only one or two messages are supported.", __func__);
return -1;
}
omsg = nmsgs == 1 ? &dummy : msg;
dmsg = nmsgs == 1 ? msg : msg + 1;
if (dmsg->flags & I2C_M_RD)
return __i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
else
return __i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
dmsg->buf, dmsg->len);
}
static const struct dm_i2c_ops fsl_i2c_ops = {
.xfer = fsl_i2c_xfer,
.probe_chip = fsl_i2c_probe_chip,
.set_bus_speed = fsl_i2c_set_bus_speed,
};
static const struct udevice_id fsl_i2c_ids[] = {
{ .compatible = "fsl-i2c", },
{ /* sentinel */ }
};
U_BOOT_DRIVER(i2c_fsl) = {
.name = "i2c_fsl",
.id = UCLASS_I2C,
.of_match = fsl_i2c_ids,
.probe = fsl_i2c_probe,
.ofdata_to_platdata = fsl_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct fsl_i2c_dev),
.ops = &fsl_i2c_ops,
};
#endif /* CONFIG_DM_I2C */

View File

@@ -0,0 +1,346 @@
/*
* Faraday I2C Controller
*
* (C) Copyright 2010 Faraday Technology
* Dante Su <dantesu@faraday-tech.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <i2c.h>
#include "fti2c010.h"
#ifndef CONFIG_SYS_I2C_SPEED
#define CONFIG_SYS_I2C_SPEED 5000
#endif
#ifndef CONFIG_SYS_I2C_SLAVE
#define CONFIG_SYS_I2C_SLAVE 0
#endif
#ifndef CONFIG_FTI2C010_CLOCK
#define CONFIG_FTI2C010_CLOCK clk_get_rate("I2C")
#endif
#ifndef CONFIG_FTI2C010_TIMEOUT
#define CONFIG_FTI2C010_TIMEOUT 10 /* ms */
#endif
/* 7-bit dev address + 1-bit read/write */
#define I2C_RD(dev) ((((dev) << 1) & 0xfe) | 1)
#define I2C_WR(dev) (((dev) << 1) & 0xfe)
struct fti2c010_chip {
struct fti2c010_regs *regs;
};
static struct fti2c010_chip chip_list[] = {
{
.regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE,
},
#ifdef CONFIG_FTI2C010_BASE1
{
.regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE1,
},
#endif
#ifdef CONFIG_FTI2C010_BASE2
{
.regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE2,
},
#endif
#ifdef CONFIG_FTI2C010_BASE3
{
.regs = (struct fti2c010_regs *)CONFIG_FTI2C010_BASE3,
},
#endif
};
static int fti2c010_reset(struct fti2c010_chip *chip)
{
ulong ts;
int ret = -1;
struct fti2c010_regs *regs = chip->regs;
writel(CR_I2CRST, &regs->cr);
for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) {
if (!(readl(&regs->cr) & CR_I2CRST)) {
ret = 0;
break;
}
}
if (ret)
printf("fti2c010: reset timeout\n");
return ret;
}
static int fti2c010_wait(struct fti2c010_chip *chip, uint32_t mask)
{
int ret = -1;
uint32_t stat, ts;
struct fti2c010_regs *regs = chip->regs;
for (ts = get_timer(0); get_timer(ts) < CONFIG_FTI2C010_TIMEOUT; ) {
stat = readl(&regs->sr);
if ((stat & mask) == mask) {
ret = 0;
break;
}
}
return ret;
}
static unsigned int set_i2c_bus_speed(struct fti2c010_chip *chip,
unsigned int speed)
{
struct fti2c010_regs *regs = chip->regs;
unsigned int clk = CONFIG_FTI2C010_CLOCK;
unsigned int gsr = 0;
unsigned int tsr = 32;
unsigned int div, rate;
for (div = 0; div < 0x3ffff; ++div) {
/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
rate = clk / (2 * (div + 2) + gsr);
if (rate <= speed)
break;
}
writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), &regs->tgsr);
writel(CDR_DIV(div), &regs->cdr);
return rate;
}
/*
* Initialization, must be called once on start up, may be called
* repeatedly to change the speed and slave addresses.
*/
static void fti2c010_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
if (adap->init_done)
return;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
/* master init */
fti2c010_reset(chip);
set_i2c_bus_speed(chip, speed);
/* slave init, don't care */
#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
/* Call board specific i2c bus reset routine AFTER the bus has been
* initialized. Use either this callpoint or i2c_init_board;
* which is called before fti2c010_init operations.
* For details about this problem see doc/I2C_Edge_Conditions.
*/
i2c_board_late_init();
#endif
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
static int fti2c010_probe(struct i2c_adapter *adap, u8 dev)
{
struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
struct fti2c010_regs *regs = chip->regs;
int ret;
/* 1. Select slave device (7bits Address + 1bit R/W) */
writel(I2C_WR(dev), &regs->dr);
writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
/* 2. Select device register */
writel(0, &regs->dr);
writel(CR_ENABLE | CR_TBEN, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
return ret;
}
static void to_i2c_addr(u8 *buf, uint32_t addr, int alen)
{
int i, shift;
if (!buf || alen <= 0)
return;
/* MSB first */
i = 0;
shift = (alen - 1) * 8;
while (alen-- > 0) {
buf[i] = (u8)(addr >> shift);
shift -= 8;
}
}
static int fti2c010_read(struct i2c_adapter *adap,
u8 dev, uint addr, int alen, uchar *buf, int len)
{
struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
struct fti2c010_regs *regs = chip->regs;
int ret, pos;
uchar paddr[4] = { 0 };
to_i2c_addr(paddr, addr, alen);
/*
* Phase A. Set register address
*/
/* A.1 Select slave device (7bits Address + 1bit R/W) */
writel(I2C_WR(dev), &regs->dr);
writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
/* A.2 Select device register */
for (pos = 0; pos < alen; ++pos) {
uint32_t ctrl = CR_ENABLE | CR_TBEN;
writel(paddr[pos], &regs->dr);
writel(ctrl, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
}
/*
* Phase B. Get register data
*/
/* B.1 Select slave device (7bits Address + 1bit R/W) */
writel(I2C_RD(dev), &regs->dr);
writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
/* B.2 Get register data */
for (pos = 0; pos < len; ++pos) {
uint32_t ctrl = CR_ENABLE | CR_TBEN;
uint32_t stat = SR_DR;
if (pos == len - 1) {
ctrl |= CR_NAK | CR_STOP;
stat |= SR_ACK;
}
writel(ctrl, &regs->cr);
ret = fti2c010_wait(chip, stat);
if (ret)
break;
buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
}
return ret;
}
static int fti2c010_write(struct i2c_adapter *adap,
u8 dev, uint addr, int alen, u8 *buf, int len)
{
struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
struct fti2c010_regs *regs = chip->regs;
int ret, pos;
uchar paddr[4] = { 0 };
to_i2c_addr(paddr, addr, alen);
/*
* Phase A. Set register address
*
* A.1 Select slave device (7bits Address + 1bit R/W)
*/
writel(I2C_WR(dev), &regs->dr);
writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
/* A.2 Select device register */
for (pos = 0; pos < alen; ++pos) {
uint32_t ctrl = CR_ENABLE | CR_TBEN;
writel(paddr[pos], &regs->dr);
writel(ctrl, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
return ret;
}
/*
* Phase B. Set register data
*/
for (pos = 0; pos < len; ++pos) {
uint32_t ctrl = CR_ENABLE | CR_TBEN;
if (pos == len - 1)
ctrl |= CR_STOP;
writel(buf[pos], &regs->dr);
writel(ctrl, &regs->cr);
ret = fti2c010_wait(chip, SR_DT);
if (ret)
break;
}
return ret;
}
static unsigned int fti2c010_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
struct fti2c010_chip *chip = chip_list + adap->hwadapnr;
int ret;
fti2c010_reset(chip);
ret = set_i2c_bus_speed(chip, speed);
return ret;
}
/*
* Register i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(i2c_0, fti2c010_init, fti2c010_probe, fti2c010_read,
fti2c010_write, fti2c010_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
0)
#ifdef CONFIG_FTI2C010_BASE1
U_BOOT_I2C_ADAP_COMPLETE(i2c_1, fti2c010_init, fti2c010_probe, fti2c010_read,
fti2c010_write, fti2c010_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
1)
#endif
#ifdef CONFIG_FTI2C010_BASE2
U_BOOT_I2C_ADAP_COMPLETE(i2c_2, fti2c010_init, fti2c010_probe, fti2c010_read,
fti2c010_write, fti2c010_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
2)
#endif
#ifdef CONFIG_FTI2C010_BASE3
U_BOOT_I2C_ADAP_COMPLETE(i2c_3, fti2c010_init, fti2c010_probe, fti2c010_read,
fti2c010_write, fti2c010_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE,
3)
#endif

View File

@@ -0,0 +1,80 @@
/*
* Faraday I2C Controller
*
* (C) Copyright 2010 Faraday Technology
* Dante Su <dantesu@faraday-tech.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __FTI2C010_H
#define __FTI2C010_H
/*
* FTI2C010 registers
*/
struct fti2c010_regs {
uint32_t cr; /* 0x00: control register */
uint32_t sr; /* 0x04: status register */
uint32_t cdr; /* 0x08: clock division register */
uint32_t dr; /* 0x0c: data register */
uint32_t sar; /* 0x10: slave address register */
uint32_t tgsr;/* 0x14: time & glitch suppression register */
uint32_t bmr; /* 0x18: bus monitor register */
uint32_t rsvd[5];
uint32_t revr;/* 0x30: revision register */
};
/*
* control register
*/
#define CR_ALIRQ 0x2000 /* arbitration lost interrupt (master) */
#define CR_SAMIRQ 0x1000 /* slave address match interrupt (slave) */
#define CR_STOPIRQ 0x800 /* stop condition interrupt (slave) */
#define CR_NAKRIRQ 0x400 /* NACK response interrupt (master) */
#define CR_DRIRQ 0x200 /* rx interrupt (both) */
#define CR_DTIRQ 0x100 /* tx interrupt (both) */
#define CR_TBEN 0x80 /* tx enable (both) */
#define CR_NAK 0x40 /* NACK (both) */
#define CR_STOP 0x20 /* stop (master) */
#define CR_START 0x10 /* start (master) */
#define CR_GCEN 0x8 /* general call support (slave) */
#define CR_SCLEN 0x4 /* enable clock out (master) */
#define CR_I2CEN 0x2 /* enable I2C (both) */
#define CR_I2CRST 0x1 /* reset I2C (both) */
#define CR_ENABLE \
(CR_ALIRQ | CR_NAKRIRQ | CR_DRIRQ | CR_DTIRQ | CR_SCLEN | CR_I2CEN)
/*
* status register
*/
#define SR_CLRAL 0x400 /* clear arbitration lost */
#define SR_CLRGC 0x200 /* clear general call */
#define SR_CLRSAM 0x100 /* clear slave address match */
#define SR_CLRSTOP 0x80 /* clear stop */
#define SR_CLRNAKR 0x40 /* clear NACK respond */
#define SR_DR 0x20 /* rx ready */
#define SR_DT 0x10 /* tx done */
#define SR_BB 0x8 /* bus busy */
#define SR_BUSY 0x4 /* chip busy */
#define SR_ACK 0x2 /* ACK/NACK received */
#define SR_RW 0x1 /* set when master-rx or slave-tx mode */
/*
* clock division register
*/
#define CDR_DIV(n) ((n) & 0x3ffff)
/*
* time & glitch suppression register
*/
#define TGSR_GSR(n) (((n) & 0x7) << 10)
#define TGSR_TSR(n) ((n) & 0x3ff)
/*
* bus monitor register
*/
#define BMR_SCL 0x2 /* SCL is pull-up */
#define BMR_SDA 0x1 /* SDA is pull-up */
#endif /* __FTI2C010_H */

View File

@@ -0,0 +1,379 @@
/*
* Copyright (C) 2015 Moritz Fischer <moritz.fischer@ettus.com>
* IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2)
*
* This file is based on: drivers/i2c/zynq_i2c.c,
* with added driver-model support and code cleanup.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/types.h>
#include <linux/io.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
/* i2c register set */
struct cdns_i2c_regs {
u32 control;
u32 status;
u32 address;
u32 data;
u32 interrupt_status;
u32 transfer_size;
u32 slave_mon_pause;
u32 time_out;
u32 interrupt_mask;
u32 interrupt_enable;
u32 interrupt_disable;
};
/* Control register fields */
#define CDNS_I2C_CONTROL_RW 0x00000001
#define CDNS_I2C_CONTROL_MS 0x00000002
#define CDNS_I2C_CONTROL_NEA 0x00000004
#define CDNS_I2C_CONTROL_ACKEN 0x00000008
#define CDNS_I2C_CONTROL_HOLD 0x00000010
#define CDNS_I2C_CONTROL_SLVMON 0x00000020
#define CDNS_I2C_CONTROL_CLR_FIFO 0x00000040
#define CDNS_I2C_CONTROL_DIV_B_SHIFT 8
#define CDNS_I2C_CONTROL_DIV_B_MASK 0x00003F00
#define CDNS_I2C_CONTROL_DIV_A_SHIFT 14
#define CDNS_I2C_CONTROL_DIV_A_MASK 0x0000C000
/* Status register values */
#define CDNS_I2C_STATUS_RXDV 0x00000020
#define CDNS_I2C_STATUS_TXDV 0x00000040
#define CDNS_I2C_STATUS_RXOVF 0x00000080
#define CDNS_I2C_STATUS_BA 0x00000100
/* Interrupt register fields */
#define CDNS_I2C_INTERRUPT_COMP 0x00000001
#define CDNS_I2C_INTERRUPT_DATA 0x00000002
#define CDNS_I2C_INTERRUPT_NACK 0x00000004
#define CDNS_I2C_INTERRUPT_TO 0x00000008
#define CDNS_I2C_INTERRUPT_SLVRDY 0x00000010
#define CDNS_I2C_INTERRUPT_RXOVF 0x00000020
#define CDNS_I2C_INTERRUPT_TXOVF 0x00000040
#define CDNS_I2C_INTERRUPT_RXUNF 0x00000080
#define CDNS_I2C_INTERRUPT_ARBLOST 0x00000200
#define CDNS_I2C_FIFO_DEPTH 16
#define CDNS_I2C_TRANSFER_SIZE_MAX 255 /* Controller transfer limit */
#ifdef DEBUG
static void cdns_i2c_debug_status(struct cdns_i2c_regs *cdns_i2c)
{
int int_status;
int status;
int_status = readl(&cdns_i2c->interrupt_status);
status = readl(&cdns_i2c->status);
if (int_status || status) {
debug("Status: ");
if (int_status & CDNS_I2C_INTERRUPT_COMP)
debug("COMP ");
if (int_status & CDNS_I2C_INTERRUPT_DATA)
debug("DATA ");
if (int_status & CDNS_I2C_INTERRUPT_NACK)
debug("NACK ");
if (int_status & CDNS_I2C_INTERRUPT_TO)
debug("TO ");
if (int_status & CDNS_I2C_INTERRUPT_SLVRDY)
debug("SLVRDY ");
if (int_status & CDNS_I2C_INTERRUPT_RXOVF)
debug("RXOVF ");
if (int_status & CDNS_I2C_INTERRUPT_TXOVF)
debug("TXOVF ");
if (int_status & CDNS_I2C_INTERRUPT_RXUNF)
debug("RXUNF ");
if (int_status & CDNS_I2C_INTERRUPT_ARBLOST)
debug("ARBLOST ");
if (status & CDNS_I2C_STATUS_RXDV)
debug("RXDV ");
if (status & CDNS_I2C_STATUS_TXDV)
debug("TXDV ");
if (status & CDNS_I2C_STATUS_RXOVF)
debug("RXOVF ");
if (status & CDNS_I2C_STATUS_BA)
debug("BA ");
debug("TS%d ", readl(&cdns_i2c->transfer_size));
debug("\n");
}
}
#endif
struct i2c_cdns_bus {
int id;
unsigned int input_freq;
struct cdns_i2c_regs __iomem *regs; /* register base */
};
/* Wait for an interrupt */
static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask)
{
int timeout, int_status;
for (timeout = 0; timeout < 100; timeout++) {
udelay(100);
int_status = readl(&cdns_i2c->interrupt_status);
if (int_status & mask)
break;
}
/* Clear interrupt status flags */
writel(int_status & mask, &cdns_i2c->interrupt_status);
return int_status & mask;
}
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
unsigned int *a, unsigned int *b)
{
unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
unsigned int last_error, current_error;
/* calculate (divisor_a+1) x (divisor_b+1) */
temp = input_clk / (22 * fscl);
/*
* If the calculated value is negative or 0CDNS_I2C_DIVA_MAX,
* the fscl input is out of range. Return error.
*/
if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
return -EINVAL;
last_error = -1;
for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
continue;
div_b--;
actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
if (actual_fscl > fscl)
continue;
current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
(fscl - actual_fscl));
if (last_error > current_error) {
calc_div_a = div_a;
calc_div_b = div_b;
best_fscl = actual_fscl;
last_error = current_error;
}
}
*a = calc_div_a;
*b = calc_div_b;
*f = best_fscl;
return 0;
}
static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct i2c_cdns_bus *bus = dev_get_priv(dev);
u32 div_a = 0, div_b = 0;
unsigned long speed_p = speed;
int ret = 0;
if (speed > 400000) {
debug("%s, failed to set clock speed to %u\n", __func__,
speed);
return -EINVAL;
}
ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b);
if (ret)
return ret;
debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n",
__func__, div_a, div_b, bus->input_freq, speed, speed_p);
writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
(div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
/* Enable master mode, ack, and 7-bit addressing */
setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA);
return 0;
}
/* Probe to see if a chip is present. */
static int cdns_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct i2c_cdns_bus *i2c_bus = dev_get_priv(bus);
struct cdns_i2c_regs *regs = i2c_bus->regs;
/* Attempt to read a byte */
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
CDNS_I2C_CONTROL_RW);
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
writel(0xFF, &regs->interrupt_status);
writel(chip_addr, &regs->address);
writel(1, &regs->transfer_size);
return (cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_NACK) &
CDNS_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT;
}
static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
u32 len, bool next_is_read)
{
u8 *cur_data = data;
struct cdns_i2c_regs *regs = i2c_bus->regs;
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
CDNS_I2C_CONTROL_HOLD);
/* if next is a read, we need to clear HOLD, doesn't work */
if (next_is_read)
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_RW);
writel(0xFF, &regs->interrupt_status);
writel(addr, &regs->address);
while (len--) {
writel(*(cur_data++), &regs->data);
if (readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
if (!cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&regs->control,
CDNS_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
}
}
/* All done... release the bus */
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
/* Wait for the address and data to be sent */
if (!cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP))
return -ETIMEDOUT;
return 0;
}
static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
u32 len)
{
u32 status;
u32 i = 0;
u8 *cur_data = data;
/* TODO: Fix this */
struct cdns_i2c_regs *regs = i2c_bus->regs;
/* Check the hardware can handle the requested bytes */
if ((len < 0) || (len > CDNS_I2C_TRANSFER_SIZE_MAX))
return -EINVAL;
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
CDNS_I2C_CONTROL_RW);
/* Start reading data */
writel(addr, &regs->address);
writel(len, &regs->transfer_size);
/* Wait for data */
do {
status = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_DATA);
if (!status) {
/* Release the bus */
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
debug("Read %d bytes\n",
len - readl(&regs->transfer_size));
for (; i < len - readl(&regs->transfer_size); i++)
*(cur_data++) = readl(&regs->data);
} while (readl(&regs->transfer_size) != 0);
/* All done... release the bus */
clrbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
#ifdef DEBUG
cdns_i2c_debug_status(regs);
#endif
return 0;
}
static int cdns_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = cdns_i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = cdns_i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
static int cdns_i2c_ofdata_to_platdata(struct udevice *dev)
{
struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->regs = (struct cdns_i2c_regs *)dev_get_addr(dev);
if (!i2c_bus->regs)
return -ENOMEM;
i2c_bus->input_freq = 100000000; /* TODO hardcode input freq for now */
return 0;
}
static const struct dm_i2c_ops cdns_i2c_ops = {
.xfer = cdns_i2c_xfer,
.probe_chip = cdns_i2c_probe_chip,
.set_bus_speed = cdns_i2c_set_bus_speed,
};
static const struct udevice_id cdns_i2c_of_match[] = {
{ .compatible = "cdns,i2c-r1p10" },
{ /* end of table */ }
};
U_BOOT_DRIVER(cdns_i2c) = {
.name = "i2c-cdns",
.id = UCLASS_I2C,
.of_match = cdns_i2c_of_match,
.ofdata_to_platdata = cdns_i2c_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct i2c_cdns_bus),
.ops = &cdns_i2c_ops,
};

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
UCLASS_DRIVER(i2c_emul) = {
.id = UCLASS_I2C_EMUL,
.name = "i2c_emul",
};

View File

@@ -0,0 +1,347 @@
/*
* (C) Copyright 2015, Samsung Electronics
* Przemyslaw Marczak <p.marczak@samsung.com>
*
* This file is based on: drivers/i2c/soft-i2c.c,
* with added driver-model support and code cleanup.
*/
#include <common.h>
#include <errno.h>
#include <dm.h>
#include <i2c.h>
#include <asm/gpio.h>
#define DEFAULT_UDELAY 5
#define RETRIES 0
#define I2C_ACK 0
#define I2C_NOACK 1
DECLARE_GLOBAL_DATA_PTR;
enum {
PIN_SDA = 0,
PIN_SCL,
PIN_COUNT,
};
struct i2c_gpio_bus {
/**
* udelay - delay [us] between GPIO toggle operations,
* which is 1/4 of I2C speed clock period.
*/
int udelay;
/* sda, scl */
struct gpio_desc gpios[PIN_COUNT];
};
static int i2c_gpio_sda_get(struct gpio_desc *sda)
{
return dm_gpio_get_value(sda);
}
static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
{
if (bit)
dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
else
dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
}
static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
{
ulong flags = GPIOD_IS_OUT;
if (bit)
flags |= GPIOD_IS_OUT_ACTIVE;
dm_gpio_set_dir_flags(scl, flags);
}
static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, uchar bit)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, bit);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(2 * delay);
}
static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
int value;
i2c_gpio_scl_set(scl, 1);
udelay(delay);
value = i2c_gpio_sda_get(sda);
udelay(delay);
i2c_gpio_scl_set(scl, 0);
udelay(2 * delay);
return value;
}
/* START: High -> Low on SDA while SCL is High */
static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(delay);
i2c_gpio_sda_set(sda, 0);
udelay(delay);
}
/* STOP: Low -> High on SDA while SCL is High */
static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, 0);
udelay(delay);
i2c_gpio_scl_set(scl, 1);
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
}
/* ack should be I2C_ACK or I2C_NOACK */
static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, int ack)
{
i2c_gpio_write_bit(scl, sda, delay, ack);
i2c_gpio_scl_set(scl, 0);
udelay(delay);
}
/**
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
int j;
for (j = 0; j < 9; j++)
i2c_gpio_write_bit(scl, sda, delay, 1);
i2c_gpio_send_stop(scl, sda, delay);
}
/* Set sda high with low clock, before reading slave data */
static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
int delay)
{
i2c_gpio_scl_set(scl, 0);
udelay(delay);
i2c_gpio_sda_set(sda, 1);
udelay(delay);
}
/* Send 8 bits and look for an acknowledgement */
static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, uchar data)
{
int j;
int nack;
for (j = 0; j < 8; j++) {
i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
data <<= 1;
}
udelay(delay);
/* Look for an <ACK>(negative logic) and return it */
i2c_gpio_sda_high(scl, sda, delay);
nack = i2c_gpio_read_bit(scl, sda, delay);
return nack; /* not a nack is an ack */
}
/**
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
int delay, int ack)
{
int data;
int j;
i2c_gpio_sda_high(scl, sda, delay);
data = 0;
for (j = 0; j < 8; j++) {
data <<= 1;
data |= i2c_gpio_read_bit(scl, sda, delay);
}
i2c_gpio_send_ack(scl, sda, delay, ack);
return data;
}
/* send start and the slave chip address */
int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
uchar chip)
{
i2c_gpio_send_start(scl, sda, delay);
if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
i2c_gpio_send_stop(scl, sda, delay);
return -EIO;
}
return 0;
}
static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len,
bool end_with_repeated_start)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int failures = 0;
debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
while (len-- > 0) {
if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
failures++;
}
if (!end_with_repeated_start) {
i2c_gpio_send_stop(scl, sda, delay);
return failures;
}
if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
return failures;
}
static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
while (len-- > 0)
*buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
i2c_gpio_send_stop(scl, sda, delay);
return 0;
}
static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
if (msg->flags & I2C_M_RD) {
ret = i2c_gpio_read_data(bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int ret;
i2c_gpio_send_start(scl, sda, delay);
ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
i2c_gpio_send_stop(scl, sda, delay);
debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
__func__, dev->seq, dev->name, chip, chip_flags, ret);
return ret;
}
static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
bus->udelay = 1000000 / (speed_hz << 2);
i2c_gpio_send_reset(scl, sda, bus->udelay);
return 0;
}
static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
int ret;
ret = gpio_request_list_by_name(dev, "gpios", bus->gpios,
ARRAY_SIZE(bus->gpios), 0);
if (ret < 0)
goto error;
bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
DEFAULT_UDELAY);
return 0;
error:
error("Can't get %s gpios! Error: %d", dev->name, ret);
return ret;
}
static const struct dm_i2c_ops i2c_gpio_ops = {
.xfer = i2c_gpio_xfer,
.probe_chip = i2c_gpio_probe,
.set_bus_speed = i2c_gpio_set_bus_speed,
};
static const struct udevice_id i2c_gpio_ids[] = {
{ .compatible = "i2c-gpio" },
{ }
};
U_BOOT_DRIVER(i2c_gpio) = {
.name = "i2c-gpio",
.id = UCLASS_I2C,
.of_match = i2c_gpio_ids,
.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
.ops = &i2c_gpio_ops,
};

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
static int cur_busnum;
static int i2c_compat_get_device(uint chip_addr, int alen,
struct udevice **devp)
{
struct dm_i2c_chip *chip;
int ret;
ret = i2c_get_chip_for_busnum(cur_busnum, chip_addr, alen, devp);
if (ret)
return ret;
chip = dev_get_parent_platdata(*devp);
if (chip->offset_len != alen) {
printf("I2C chip %x: requested alen %d does not match chip offset_len %d\n",
chip_addr, alen, chip->offset_len);
return -EADDRNOTAVAIL;
}
return 0;
}
int i2c_probe(uint8_t chip_addr)
{
struct udevice *bus, *dev;
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, cur_busnum, &bus);
if (ret) {
debug("Cannot find I2C bus %d: err=%d\n", cur_busnum, ret);
return ret;
}
if (!bus)
return -ENOENT;
return dm_i2c_probe(bus, chip_addr, 0, &dev);
}
int i2c_read(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
int len)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, alen, &dev);
if (ret)
return ret;
return dm_i2c_read(dev, addr, buffer, len);
}
int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
int len)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, alen, &dev);
if (ret)
return ret;
return dm_i2c_write(dev, addr, buffer, len);
}
int i2c_get_bus_num_fdt(int node)
{
struct udevice *bus;
int ret;
ret = uclass_get_device_by_of_offset(UCLASS_I2C, node, &bus);
if (ret)
return ret;
return bus->seq;
}
unsigned int i2c_get_bus_num(void)
{
return cur_busnum;
}
int i2c_set_bus_num(unsigned int bus)
{
cur_busnum = bus;
return 0;
}
void i2c_init(int speed, int slaveaddr)
{
/* Nothing to do here - the init happens through driver model */
}
void board_i2c_init(const void *blob)
{
/* Nothing to do here - the init happens through driver model */
}
uint8_t i2c_reg_read(uint8_t chip_addr, uint8_t offset)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, 1, &dev);
if (ret)
return 0xff;
return dm_i2c_reg_read(dev, offset);
}
void i2c_reg_write(uint8_t chip_addr, uint8_t offset, uint8_t val)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, 1, &dev);
if (!ret)
dm_i2c_reg_write(dev, offset, val);
}

View File

@@ -0,0 +1,531 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <malloc.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
#define I2C_MAX_OFFSET_LEN 4
/* Useful debugging function */
void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
{
int i;
for (i = 0; i < nmsgs; i++) {
struct i2c_msg *m = &msg[i];
printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
msg->addr, msg->len);
if (!(m->flags & I2C_M_RD))
printf(": %x", m->buf[0]);
printf("\n");
}
}
/**
* i2c_setup_offset() - Set up a new message with a chip offset
*
* @chip: Chip to use
* @offset: Byte offset within chip
* @offset_buf: Place to put byte offset
* @msg: Message buffer
* @return 0 if OK, -EADDRNOTAVAIL if the offset length is 0. In that case the
* message is still set up but will not contain an offset.
*/
static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
uint8_t offset_buf[], struct i2c_msg *msg)
{
int offset_len;
msg->addr = chip->chip_addr;
msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
msg->len = chip->offset_len;
msg->buf = offset_buf;
if (!chip->offset_len)
return -EADDRNOTAVAIL;
assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
offset_len = chip->offset_len;
while (offset_len--)
*offset_buf++ = offset >> (8 * offset_len);
return 0;
}
static int i2c_read_bytewise(struct udevice *dev, uint offset,
uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
int ret;
int i;
for (i = 0; i < len; i++) {
if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
return -EINVAL;
ptr = msg + 1;
ptr->addr = chip->chip_addr;
ptr->flags = msg->flags | I2C_M_RD;
ptr->len = 1;
ptr->buf = &buffer[i];
ptr++;
ret = ops->xfer(bus, msg, ptr - msg);
if (ret)
return ret;
}
return 0;
}
static int i2c_write_bytewise(struct udevice *dev, uint offset,
const uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
int ret;
int i;
for (i = 0; i < len; i++) {
if (i2c_setup_offset(chip, offset + i, buf, msg))
return -EINVAL;
buf[msg->len++] = buffer[i];
ret = ops->xfer(bus, msg, 1);
if (ret)
return ret;
}
return 0;
}
int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
int msg_count;
if (!ops->xfer)
return -ENOSYS;
if (chip->flags & DM_I2C_CHIP_RD_ADDRESS)
return i2c_read_bytewise(dev, offset, buffer, len);
ptr = msg;
if (!i2c_setup_offset(chip, offset, offset_buf, ptr))
ptr++;
if (len) {
ptr->addr = chip->chip_addr;
ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
ptr->flags |= I2C_M_RD;
ptr->len = len;
ptr->buf = buffer;
ptr++;
}
msg_count = ptr - msg;
return ops->xfer(bus, msg, msg_count);
}
int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
int len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
if (!ops->xfer)
return -ENOSYS;
if (chip->flags & DM_I2C_CHIP_WR_ADDRESS)
return i2c_write_bytewise(dev, offset, buffer, len);
/*
* The simple approach would be to send two messages here: one to
* set the offset and one to write the bytes. However some drivers
* will not be expecting this, and some chips won't like how the
* driver presents this on the I2C bus.
*
* The API does not support separate offset and data. We could extend
* it with a flag indicating that there is data in the next message
* that needs to be processed in the same transaction. We could
* instead add an additional buffer to each message. For now, handle
* this in the uclass since it isn't clear what the impact on drivers
* would be with this extra complication. Unfortunately this means
* copying the message.
*
* Use the stack for small messages, malloc() for larger ones. We
* need to allow space for the offset (up to 4 bytes) and the message
* itself.
*/
if (len < 64) {
uint8_t buf[I2C_MAX_OFFSET_LEN + len];
i2c_setup_offset(chip, offset, buf, msg);
msg->len += len;
memcpy(buf + chip->offset_len, buffer, len);
return ops->xfer(bus, msg, 1);
} else {
uint8_t *buf;
int ret;
buf = malloc(I2C_MAX_OFFSET_LEN + len);
if (!buf)
return -ENOMEM;
i2c_setup_offset(chip, offset, buf, msg);
msg->len += len;
memcpy(buf + chip->offset_len, buffer, len);
ret = ops->xfer(bus, msg, 1);
free(buf);
return ret;
}
}
int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
if (!ops->xfer)
return -ENOSYS;
return ops->xfer(bus, msg, nmsgs);
}
int dm_i2c_reg_read(struct udevice *dev, uint offset)
{
uint8_t val;
int ret;
ret = dm_i2c_read(dev, offset, &val, 1);
if (ret < 0)
return ret;
return val;
}
int dm_i2c_reg_write(struct udevice *dev, uint offset, uint value)
{
uint8_t val = value;
return dm_i2c_write(dev, offset, &val, 1);
}
/**
* i2c_probe_chip() - probe for a chip on a bus
*
* @bus: Bus to probe
* @chip_addr: Chip address to probe
* @flags: Flags for the chip
* @return 0 if found, -ENOSYS if the driver is invalid, -EREMOTEIO if the chip
* does not respond to probe
*/
static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
enum dm_i2c_chip_flags chip_flags)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
int ret;
if (ops->probe_chip) {
ret = ops->probe_chip(bus, chip_addr, chip_flags);
if (!ret || ret != -ENOSYS)
return ret;
}
if (!ops->xfer)
return -ENOSYS;
/* Probe with a zero-length message */
msg->addr = chip_addr;
msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
msg->len = 0;
msg->buf = NULL;
return ops->xfer(bus, msg, 1);
}
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct dm_i2c_chip *chip;
char name[30], *str;
struct udevice *dev;
int ret;
snprintf(name, sizeof(name), "generic_%x", chip_addr);
str = strdup(name);
if (!str)
return -ENOMEM;
ret = device_bind_driver(bus, "i2c_generic_chip_drv", str, &dev);
debug("%s: device_bind_driver: ret=%d\n", __func__, ret);
if (ret)
goto err_bind;
/* Tell the device what we know about it */
chip = dev_get_parent_platdata(dev);
chip->chip_addr = chip_addr;
chip->offset_len = offset_len;
ret = device_probe(dev);
debug("%s: device_probe: ret=%d\n", __func__, ret);
if (ret)
goto err_probe;
*devp = dev;
return 0;
err_probe:
/*
* If the device failed to probe, unbind it. There is nothing there
* on the bus so we don't want to leave it lying around
*/
device_unbind(dev);
err_bind:
free(str);
return ret;
}
int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *dev;
debug("%s: Searching bus '%s' for address %02x: ", __func__,
bus->name, chip_addr);
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
if (chip->chip_addr == chip_addr) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
if (ret)
return ret;
*devp = dev;
return 0;
}
}
debug("not found\n");
return i2c_bind_driver(bus, chip_addr, offset_len, devp);
}
int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *bus;
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus);
if (ret) {
debug("Cannot find I2C bus %d\n", busnum);
return ret;
}
ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
if (ret) {
debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
busnum);
return ret;
}
return 0;
}
int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
struct udevice **devp)
{
int ret;
*devp = NULL;
/* First probe that chip */
ret = i2c_probe_chip(bus, chip_addr, chip_flags);
debug("%s: bus='%s', address %02x, ret=%d\n", __func__, bus->name,
chip_addr, ret);
if (ret)
return ret;
/* The chip was found, see if we have a driver, and probe it */
ret = i2c_get_chip(bus, chip_addr, 1, devp);
debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
return ret;
}
int dm_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
int ret;
/*
* If we have a method, call it. If not then the driver probably wants
* to deal with speed changes on the next transfer. It can easily read
* the current speed from this uclass
*/
if (ops->set_bus_speed) {
ret = ops->set_bus_speed(bus, speed);
if (ret)
return ret;
}
i2c->speed_hz = speed;
return 0;
}
int dm_i2c_get_bus_speed(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
if (!ops->get_bus_speed)
return i2c->speed_hz;
return ops->get_bus_speed(bus);
}
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
struct udevice *bus = dev->parent;
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int ret;
if (ops->set_flags) {
ret = ops->set_flags(dev, flags);
if (ret)
return ret;
}
chip->flags = flags;
return 0;
}
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
*flagsp = chip->flags;
return 0;
}
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
return -EINVAL;
chip->offset_len = offset_len;
return 0;
}
int i2c_get_chip_offset_len(struct udevice *dev)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
return chip->offset_len;
}
int i2c_deblock(struct udevice *bus)
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
/*
* We could implement a software deblocking here if we could get
* access to the GPIOs used by I2C, and switch them to GPIO mode
* and then back to I2C. This is somewhat beyond our powers in
* driver model at present, so for now just fail.
*
* See https://patchwork.ozlabs.org/patch/399040/
*/
if (!ops->deblock)
return -ENOSYS;
return ops->deblock(bus);
}
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip)
{
chip->offset_len = fdtdec_get_int(gd->fdt_blob, node,
"u-boot,i2c-offset-len", 1);
chip->flags = 0;
chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
if (chip->chip_addr == -1) {
debug("%s: I2C Node '%s' has no 'reg' property\n", __func__,
fdt_get_name(blob, node, NULL));
return -EINVAL;
}
return 0;
}
static int i2c_post_probe(struct udevice *dev)
{
struct dm_i2c_bus *i2c = dev_get_uclass_priv(dev);
i2c->speed_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 100000);
return dm_i2c_set_bus_speed(dev, i2c->speed_hz);
}
static int i2c_post_bind(struct udevice *dev)
{
/* Scan the bus for devices */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
static int i2c_child_post_bind(struct udevice *dev)
{
struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
if (dev->of_offset == -1)
return 0;
return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
}
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = i2c_post_bind,
.post_probe = i2c_post_probe,
.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_post_bind = i2c_child_post_bind,
};
UCLASS_DRIVER(i2c_generic) = {
.id = UCLASS_I2C_GENERIC,
.name = "i2c_generic",
};
U_BOOT_DRIVER(i2c_generic_chip_drv) = {
.name = "i2c_generic_chip_drv",
.id = UCLASS_I2C_GENERIC,
};

View File

@@ -0,0 +1,365 @@
/*
* Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
#include <mapmem.h>
struct uniphier_fi2c_regs {
u32 cr; /* control register */
#define I2C_CR_MST (1 << 3) /* master mode */
#define I2C_CR_STA (1 << 2) /* start condition */
#define I2C_CR_STO (1 << 1) /* stop condition */
#define I2C_CR_NACK (1 << 0) /* not ACK */
u32 dttx; /* send FIFO (write-only) */
#define dtrx dttx /* receive FIFO (read-only) */
#define I2C_DTTX_CMD (1 << 8) /* send command (slave addr) */
#define I2C_DTTX_RD (1 << 0) /* read */
u32 __reserved; /* no register at offset 0x08 */
u32 slad; /* slave address */
u32 cyc; /* clock cycle control */
u32 lctl; /* clock low period control */
u32 ssut; /* restart/stop setup time control */
u32 dsut; /* data setup time control */
u32 intr; /* interrupt status */
u32 ie; /* interrupt enable */
u32 ic; /* interrupt clear */
#define I2C_INT_TE (1 << 9) /* TX FIFO empty */
#define I2C_INT_RB (1 << 4) /* received specified bytes */
#define I2C_INT_NA (1 << 2) /* no answer */
#define I2C_INT_AL (1 << 1) /* arbitration lost */
u32 sr; /* status register */
#define I2C_SR_DB (1 << 12) /* device busy */
#define I2C_SR_BB (1 << 8) /* bus busy */
#define I2C_SR_RFF (1 << 3) /* Rx FIFO full */
#define I2C_SR_RNE (1 << 2) /* Rx FIFO not empty */
#define I2C_SR_TNF (1 << 1) /* Tx FIFO not full */
#define I2C_SR_TFE (1 << 0) /* Tx FIFO empty */
u32 __reserved2; /* no register at offset 0x30 */
u32 rst; /* reset control */
#define I2C_RST_TBRST (1 << 2) /* clear Tx FIFO */
#define I2C_RST_RBRST (1 << 1) /* clear Rx FIFO */
#define I2C_RST_RST (1 << 0) /* forcible bus reset */
u32 bm; /* bus monitor */
u32 noise; /* noise filter control */
u32 tbc; /* Tx byte count setting */
u32 rbc; /* Rx byte count setting */
u32 tbcm; /* Tx byte count monitor */
u32 rbcm; /* Rx byte count monitor */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1) /* normal operation */
#define I2C_BRST_RSCLO (1 << 0) /* release SCL low fixing */
};
#define FIOCLK 50000000
struct uniphier_fi2c_dev {
struct uniphier_fi2c_regs __iomem *regs; /* register base */
unsigned long fioclk; /* internal operation clock */
unsigned long timeout; /* time out (us) */
};
static int poll_status(u32 __iomem *reg, u32 flag)
{
int wait = 1000000; /* 1 sec is long enough */
while (readl(reg) & flag) {
if (wait-- < 0)
return -EREMOTEIO;
udelay(1);
}
return 0;
}
static int reset_bus(struct uniphier_fi2c_regs __iomem *regs)
{
int ret;
/* bus forcible reset */
writel(I2C_RST_RST, &regs->rst);
ret = poll_status(&regs->rst, I2C_RST_RST);
if (ret < 0)
debug("error: fail to reset I2C controller\n");
return ret;
}
static int check_device_busy(struct uniphier_fi2c_regs __iomem *regs)
{
int ret;
ret = poll_status(&regs->sr, I2C_SR_DB);
if (ret < 0) {
debug("error: device busy too long. reset...\n");
ret = reset_bus(regs);
}
return ret;
}
static int uniphier_fi2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
int ret;
addr = dev_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = map_sysmem(addr, SZ_128);
if (!priv->regs)
return -ENOMEM;
priv->fioclk = FIOCLK;
/* bus forcible reset */
ret = reset_bus(priv->regs);
if (ret < 0)
return ret;
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
return 0;
}
static int uniphier_fi2c_remove(struct udevice *dev)
{
struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
unmap_sysmem(priv->regs);
return 0;
}
static int wait_for_irq(struct uniphier_fi2c_dev *dev, u32 flags,
bool *stop)
{
u32 irq;
unsigned long wait = dev->timeout;
int ret = -EREMOTEIO;
do {
udelay(1);
irq = readl(&dev->regs->intr);
} while (!(irq & flags) && wait--);
if (wait < 0) {
debug("error: time out\n");
return ret;
}
if (irq & I2C_INT_AL) {
debug("error: arbitration lost\n");
*stop = false;
return ret;
}
if (irq & I2C_INT_NA) {
debug("error: no answer\n");
return ret;
}
return 0;
}
static int issue_stop(struct uniphier_fi2c_dev *dev, int old_ret)
{
int ret;
debug("stop condition\n");
writel(I2C_CR_MST | I2C_CR_STO, &dev->regs->cr);
ret = poll_status(&dev->regs->sr, I2C_SR_DB);
if (ret < 0)
debug("error: device busy after operation\n");
return old_ret ? old_ret : ret;
}
static int uniphier_fi2c_transmit(struct uniphier_fi2c_dev *dev, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
debug("start condition\n");
writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
while (len--) {
debug("sending %x\n", *buf);
writel(*buf++, &regs->dttx);
writel(irq_flags, &regs->ic);
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(dev, ret);
return ret;
}
static int uniphier_fi2c_receive(struct uniphier_fi2c_dev *dev, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret = 0;
const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
/*
* In case 'len == 0', only the slave address should be sent
* for probing, which is covered by the transmit function.
*/
if (len == 0)
return uniphier_fi2c_transmit(dev, addr, len, buf, stop);
writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
writel(0, &regs->rbc);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
debug("start condition\n");
writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
&regs->cr);
while (len--) {
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
*buf++ = readl(&regs->dtrx);
debug("received %x\n", *(buf - 1));
if (len == 1)
writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
writel(irq_flags, &regs->ic);
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(dev, ret);
return ret;
}
static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret;
struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
bool stop;
ret = check_device_busy(dev->regs);
if (ret < 0)
return ret;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_fi2c_receive(dev, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_fi2c_transmit(dev, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
int ret;
unsigned int clk_count;
struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
ret = check_device_busy(dev->regs);
if (ret < 0)
return ret;
/* make sure the bus is idle when changing the frequency */
writel(I2C_BRST_RSCLO, &regs->brst);
clk_count = dev->fioclk / speed;
writel(clk_count, &regs->cyc);
writel(clk_count / 2, &regs->lctl);
writel(clk_count / 2, &regs->ssut);
writel(clk_count / 16, &regs->dsut);
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec.
* This time out value is long enough.
*/
dev->timeout = 100000000L / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_fi2c_ops = {
.xfer = uniphier_fi2c_xfer,
.set_bus_speed = uniphier_fi2c_set_bus_speed,
};
static const struct udevice_id uniphier_fi2c_of_match[] = {
{ .compatible = "socionext,uniphier-fi2c" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(uniphier_fi2c) = {
.name = "uniphier-fi2c",
.id = UCLASS_I2C,
.of_match = uniphier_fi2c_of_match,
.probe = uniphier_fi2c_probe,
.remove = uniphier_fi2c_remove,
.priv_auto_alloc_size = sizeof(struct uniphier_fi2c_dev),
.ops = &uniphier_fi2c_ops,
};

View File

@@ -0,0 +1,226 @@
/*
* Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/sizes.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
#include <mapmem.h>
struct uniphier_i2c_regs {
u32 dtrm; /* data transmission */
#define I2C_DTRM_STA (1 << 10)
#define I2C_DTRM_STO (1 << 9)
#define I2C_DTRM_NACK (1 << 8)
#define I2C_DTRM_RD (1 << 0)
u32 drec; /* data reception */
#define I2C_DREC_STS (1 << 12)
#define I2C_DREC_LRB (1 << 11)
#define I2C_DREC_LAB (1 << 9)
u32 myad; /* slave address */
u32 clk; /* clock frequency control */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1)
#define I2C_BRST_BRST (1 << 0)
u32 hold; /* hold time control */
u32 bsts; /* bus status monitor */
u32 noise; /* noise filter control */
u32 setup; /* setup time control */
};
#define IOBUS_FREQ 100000000
struct uniphier_i2c_dev {
struct uniphier_i2c_regs __iomem *regs; /* register base */
unsigned long input_clk; /* master clock (Hz) */
unsigned long wait_us; /* wait for every byte transfer (us) */
};
static int uniphier_i2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
struct uniphier_i2c_dev *priv = dev_get_priv(dev);
addr = dev_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = map_sysmem(addr, SZ_64);
if (!priv->regs)
return -ENOMEM;
priv->input_clk = IOBUS_FREQ;
/* deassert reset */
writel(0x3, &priv->regs->brst);
return 0;
}
static int uniphier_i2c_remove(struct udevice *dev)
{
struct uniphier_i2c_dev *priv = dev_get_priv(dev);
unmap_sysmem(priv->regs);
return 0;
}
static int send_and_recv_byte(struct uniphier_i2c_dev *dev, u32 dtrm)
{
writel(dtrm, &dev->regs->dtrm);
/*
* This controller only provides interruption to inform the completion
* of each byte transfer. (No status register to poll it.)
* Unfortunately, U-Boot does not have a good support of interrupt.
* Wait for a while.
*/
udelay(dev->wait_us);
return readl(&dev->regs->drec);
}
static int send_byte(struct uniphier_i2c_dev *dev, u32 dtrm, bool *stop)
{
int ret = 0;
u32 drec;
drec = send_and_recv_byte(dev, dtrm);
if (drec & I2C_DREC_LAB) {
debug("uniphier_i2c: bus arbitration failed\n");
*stop = false;
ret = -EREMOTEIO;
}
if (drec & I2C_DREC_LRB) {
debug("uniphier_i2c: slave did not return ACK\n");
ret = -EREMOTEIO;
}
return ret;
}
static int uniphier_i2c_transmit(struct uniphier_i2c_dev *dev, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--) {
ret = send_byte(dev, I2C_DTRM_NACK | *buf++, stop);
if (ret < 0)
goto fail;
}
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
return ret;
}
static int uniphier_i2c_receive(struct uniphier_i2c_dev *dev, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK |
I2C_DTRM_RD | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--)
*buf++ = send_and_recv_byte(dev, len ? 0 : I2C_DTRM_NACK);
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
return ret;
}
static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret = 0;
struct uniphier_i2c_dev *dev = dev_get_priv(bus);
bool stop;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_i2c_receive(dev, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_i2c_transmit(dev, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct uniphier_i2c_dev *priv = dev_get_priv(bus);
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
/* bus reset: make sure the bus is idle when change the frequency */
writel(0x1, &priv->regs->brst);
writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
&priv->regs->clk);
writel(0x3, &priv->regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec. For safety, wait more than double.
*/
priv->wait_us = 20000000 / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_i2c_ops = {
.xfer = uniphier_i2c_xfer,
.set_bus_speed = uniphier_i2c_set_bus_speed,
};
static const struct udevice_id uniphier_i2c_of_match[] = {
{ .compatible = "socionext,uniphier-i2c" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(uniphier_i2c) = {
.name = "uniphier-i2c",
.id = UCLASS_I2C,
.of_match = uniphier_i2c_of_match,
.probe = uniphier_i2c_probe,
.remove = uniphier_i2c_remove,
.priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev),
.ops = &uniphier_i2c_ops,
};

View File

@@ -0,0 +1,404 @@
/*
* Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
*
* (C) Copyright 2012
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
*
* Multibus/multiadapter I2C core functions (wrappers)
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
struct i2c_adapter *i2c_get_adapter(int index)
{
struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
i2c);
int max = ll_entry_count(struct i2c_adapter, i2c);
int i;
if (index >= max) {
printf("Error, wrong i2c adapter %d max %d possible\n",
index, max);
return i2c_adap_p;
}
if (index == 0)
return i2c_adap_p;
for (i = 0; i < index; i++)
i2c_adap_p++;
return i2c_adap_p;
}
#if !defined(CONFIG_SYS_I2C_DIRECT_BUS)
struct i2c_bus_hose i2c_bus[CONFIG_SYS_NUM_I2C_BUSES] =
CONFIG_SYS_I2C_BUSES;
#endif
DECLARE_GLOBAL_DATA_PTR;
void i2c_reloc_fixup(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
i2c);
struct i2c_adapter *tmp = i2c_adap_p;
int max = ll_entry_count(struct i2c_adapter, i2c);
int i;
unsigned long addr;
if (gd->reloc_off == 0)
return;
for (i = 0; i < max; i++) {
/* i2c_init() */
addr = (unsigned long)i2c_adap_p->init;
addr += gd->reloc_off;
i2c_adap_p->init = (void *)addr;
/* i2c_probe() */
addr = (unsigned long)i2c_adap_p->probe;
addr += gd->reloc_off;
i2c_adap_p->probe = (void *)addr;
/* i2c_read() */
addr = (unsigned long)i2c_adap_p->read;
addr += gd->reloc_off;
i2c_adap_p->read = (void *)addr;
/* i2c_write() */
addr = (unsigned long)i2c_adap_p->write;
addr += gd->reloc_off;
i2c_adap_p->write = (void *)addr;
/* i2c_set_bus_speed() */
addr = (unsigned long)i2c_adap_p->set_bus_speed;
addr += gd->reloc_off;
i2c_adap_p->set_bus_speed = (void *)addr;
/* name */
addr = (unsigned long)i2c_adap_p->name;
addr += gd->reloc_off;
i2c_adap_p->name = (char *)addr;
tmp++;
i2c_adap_p = tmp;
}
#endif
}
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
/*
* i2c_mux_set()
* -------------
*
* This turns on the given channel on I2C multiplexer chip connected to
* a given I2C adapter directly or via other multiplexers. In the latter
* case the entire multiplexer chain must be initialized first starting
* with the one connected directly to the adapter. When disabling a chain
* muxes must be programmed in reverse order, starting with the one
* farthest from the adapter.
*
* mux_id is the multiplexer chip type from defined in i2c.h. So far only
* NXP (Philips) PCA954x multiplexers are supported. Switches are NOT
* supported (anybody uses them?)
*/
static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
int channel)
{
uint8_t buf;
int ret;
/* channel < 0 - turn off the mux */
if (channel < 0) {
buf = 0;
ret = adap->write(adap, chip, 0, 0, &buf, 1);
if (ret)
printf("%s: Could not turn off the mux.\n", __func__);
return ret;
}
switch (mux_id) {
case I2C_MUX_PCA9540_ID:
case I2C_MUX_PCA9542_ID:
if (channel > 1)
return -1;
buf = (uint8_t)((channel & 0x01) | (1 << 2));
break;
case I2C_MUX_PCA9544_ID:
if (channel > 3)
return -1;
buf = (uint8_t)((channel & 0x03) | (1 << 2));
break;
case I2C_MUX_PCA9547_ID:
if (channel > 7)
return -1;
buf = (uint8_t)((channel & 0x07) | (1 << 3));
break;
case I2C_MUX_PCA9548_ID:
if (channel > 7)
return -1;
buf = (uint8_t)(0x01 << channel);
break;
default:
printf("%s: wrong mux id: %d\n", __func__, mux_id);
return -1;
}
ret = adap->write(adap, chip, 0, 0, &buf, 1);
if (ret)
printf("%s: could not set mux: id: %d chip: %x channel: %d\n",
__func__, mux_id, chip, channel);
return ret;
}
static int i2c_mux_set_all(void)
{
struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
int i;
/* Connect requested bus if behind muxes */
if (i2c_bus_tmp->next_hop[0].chip != 0) {
/* Set all muxes along the path to that bus */
for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) {
int ret;
if (i2c_bus_tmp->next_hop[i].chip == 0)
break;
ret = i2c_mux_set(I2C_ADAP,
i2c_bus_tmp->next_hop[i].mux.id,
i2c_bus_tmp->next_hop[i].chip,
i2c_bus_tmp->next_hop[i].channel);
if (ret != 0)
return ret;
}
}
return 0;
}
static int i2c_mux_disconnect_all(void)
{
struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
int i;
uint8_t buf = 0;
if (I2C_ADAP->init_done == 0)
return 0;
/* Disconnect current bus (turn off muxes if any) */
if ((i2c_bus_tmp->next_hop[0].chip != 0) &&
(I2C_ADAP->init_done != 0)) {
i = CONFIG_SYS_I2C_MAX_HOPS;
do {
uint8_t chip;
int ret;
chip = i2c_bus_tmp->next_hop[--i].chip;
if (chip == 0)
continue;
ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
if (ret != 0) {
printf("i2c: mux disconnect error\n");
return ret;
}
} while (i > 0);
}
return 0;
}
#endif
/*
* i2c_init_bus():
* ---------------
*
* Initializes one bus. Will initialize the parent adapter. No current bus
* changes, no mux (if any) setup.
*/
static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr)
{
if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES)
return;
I2C_ADAP->init(I2C_ADAP, speed, slaveaddr);
if (gd->flags & GD_FLG_RELOC) {
I2C_ADAP->init_done = 1;
I2C_ADAP->speed = speed;
I2C_ADAP->slaveaddr = slaveaddr;
}
}
/* implement possible board specific board init */
__weak void i2c_init_board(void)
{
}
/* implement possible for i2c specific early i2c init */
__weak void i2c_early_init_f(void)
{
}
/*
* i2c_init_all():
*
* not longer needed, will deleted. Actual init the SPD_BUS
* for compatibility.
* i2c_adap[] must be initialized beforehead with function pointers and
* data, including speed and slaveaddr.
*/
void i2c_init_all(void)
{
i2c_init_board();
i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
return;
}
/*
* i2c_get_bus_num():
* ------------------
*
* Returns index of currently active I2C bus. Zero-based.
*/
unsigned int i2c_get_bus_num(void)
{
return gd->cur_i2c_bus;
}
/*
* i2c_set_bus_num():
* ------------------
*
* Change the active I2C bus. Subsequent read/write calls will
* go to this one. Sets all of the muxes in a proper condition
* if that bus is behind muxes.
* If previously selected bus is behind the muxes turns off all the
* muxes along the path to that bus.
*
* bus - bus index, zero based
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_set_bus_num(unsigned int bus)
{
int max;
if ((bus == I2C_BUS) && (I2C_ADAP->init_done > 0))
return 0;
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
if (bus >= CONFIG_SYS_NUM_I2C_BUSES)
return -1;
#endif
max = ll_entry_count(struct i2c_adapter, i2c);
if (I2C_ADAPTER(bus) >= max) {
printf("Error, wrong i2c adapter %d max %d possible\n",
I2C_ADAPTER(bus), max);
return -2;
}
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
i2c_mux_disconnect_all();
#endif
gd->cur_i2c_bus = bus;
if (I2C_ADAP->init_done == 0)
i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr);
#ifndef CONFIG_SYS_I2C_DIRECT_BUS
i2c_mux_set_all();
#endif
return 0;
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uint8_t chip)
{
return I2C_ADAP->probe(I2C_ADAP, chip);
}
/*
* Read/Write interface:
* chip: I2C chip address, range 0..127
* addr: Memory (register) address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Where to read/write the data
* len: How many bytes to read/write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read(uint8_t chip, unsigned int addr, int alen,
uint8_t *buffer, int len)
{
return I2C_ADAP->read(I2C_ADAP, chip, addr, alen, buffer, len);
}
int i2c_write(uint8_t chip, unsigned int addr, int alen,
uint8_t *buffer, int len)
{
return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len);
}
unsigned int i2c_set_bus_speed(unsigned int speed)
{
unsigned int ret;
if (I2C_ADAP->set_bus_speed == NULL)
return 0;
ret = I2C_ADAP->set_bus_speed(I2C_ADAP, speed);
if (gd->flags & GD_FLG_RELOC)
I2C_ADAP->speed = (ret == 0) ? speed : 0;
return ret;
}
unsigned int i2c_get_bus_speed(void)
{
struct i2c_adapter *cur = I2C_ADAP;
return cur->speed;
}
uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
{
uint8_t buf;
#ifdef CONFIG_8xx
/* MPC8xx needs this. Maybe one day we can get rid of it. */
/* maybe it is now the time for it ... */
i2c_set_bus_num(i2c_get_bus_num());
#endif
i2c_read(addr, reg, 1, &buf, 1);
#ifdef DEBUG
printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
__func__, i2c_get_bus_num(), addr, reg, buf);
#endif
return buf;
}
void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
{
#ifdef CONFIG_8xx
/* MPC8xx needs this. Maybe one day we can get rid of it. */
/* maybe it is now the time for it ... */
i2c_set_bus_num(i2c_get_bus_num());
#endif
#ifdef DEBUG
printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
__func__, i2c_get_bus_num(), addr, reg, val);
#endif
i2c_write(addr, reg, 1, &val, 1);
}
__weak void i2c_init(int speed, int slaveaddr)
{
i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr);
}

View File

@@ -0,0 +1,257 @@
/*
* (C) Copyright 2013
* Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <gdsys_fpga.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SYS_I2C_IHS_DUAL
#define I2C_SET_REG(fld, val) \
do { \
if (I2C_ADAP_HWNR & 0x10) \
FPGA_SET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
else \
FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
} while (0)
#else
#define I2C_SET_REG(fld, val) \
FPGA_SET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
#endif
#ifdef CONFIG_SYS_I2C_IHS_DUAL
#define I2C_GET_REG(fld, val) \
do { \
if (I2C_ADAP_HWNR & 0x10) \
FPGA_GET_REG(I2C_ADAP_HWNR & 0xf, i2c1.fld, val); \
else \
FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val); \
} while (0)
#else
#define I2C_GET_REG(fld, val) \
FPGA_GET_REG(I2C_ADAP_HWNR, i2c0.fld, val)
#endif
enum {
I2CINT_ERROR_EV = 1 << 13,
I2CINT_TRANSMIT_EV = 1 << 14,
I2CINT_RECEIVE_EV = 1 << 15,
};
enum {
I2CMB_WRITE = 1 << 10,
I2CMB_2BYTE = 1 << 11,
I2CMB_HOLD_BUS = 1 << 13,
I2CMB_NATIVE = 2 << 14,
};
static int wait_for_int(bool read)
{
u16 val;
unsigned int ctr = 0;
I2C_GET_REG(interrupt_status, &val);
while (!(val & (I2CINT_ERROR_EV
| (read ? I2CINT_RECEIVE_EV : I2CINT_TRANSMIT_EV)))) {
udelay(10);
if (ctr++ > 5000) {
return 1;
}
I2C_GET_REG(interrupt_status, &val);
}
return (val & I2CINT_ERROR_EV) ? 1 : 0;
}
static int ihs_i2c_transfer(uchar chip, uchar *buffer, int len, bool read,
bool is_last)
{
u16 val;
I2C_SET_REG(interrupt_status, I2CINT_ERROR_EV
| I2CINT_RECEIVE_EV | I2CINT_TRANSMIT_EV);
I2C_GET_REG(interrupt_status, &val);
if (!read && len) {
val = buffer[0];
if (len > 1)
val |= buffer[1] << 8;
I2C_SET_REG(write_mailbox_ext, val);
}
I2C_SET_REG(write_mailbox,
I2CMB_NATIVE
| (read ? 0 : I2CMB_WRITE)
| (chip << 1)
| ((len > 1) ? I2CMB_2BYTE : 0)
| (is_last ? 0 : I2CMB_HOLD_BUS));
if (wait_for_int(read))
return 1;
if (read) {
I2C_GET_REG(read_mailbox_ext, &val);
buffer[0] = val & 0xff;
if (len > 1)
buffer[1] = val >> 8;
}
return 0;
}
static int ihs_i2c_address(uchar chip, uint addr, int alen, bool hold_bus)
{
int shift = (alen-1) * 8;
while (alen) {
int transfer = min(alen, 2);
uchar buf[2];
bool is_last = alen <= transfer;
buf[0] = addr >> shift;
if (alen > 1)
buf[1] = addr >> (shift - 8);
if (ihs_i2c_transfer(chip, buf, transfer, false,
hold_bus ? false : is_last))
return 1;
shift -= 16;
alen -= transfer;
}
return 0;
}
static int ihs_i2c_access(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len, bool read)
{
if (len <= 0)
return 1;
if (ihs_i2c_address(chip, addr, alen, len))
return 1;
while (len) {
int transfer = min(len, 2);
if (ihs_i2c_transfer(chip, buffer, transfer, read,
len <= transfer))
return 1;
buffer += transfer;
addr += transfer;
len -= transfer;
}
return 0;
}
static void ihs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
}
static int ihs_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar buffer[2];
if (ihs_i2c_transfer(chip, buffer, 0, true, true))
return 1;
return 0;
}
static int ihs_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
return ihs_i2c_access(adap, chip, addr, alen, buffer, len, true);
}
static int ihs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
return ihs_i2c_access(adap, chip, addr, alen, buffer, len, false);
}
static unsigned int ihs_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
if (speed != adap->speed)
return 1;
return speed;
}
/*
* Register IHS i2c adapters
*/
#ifdef CONFIG_SYS_I2C_IHS_CH0
U_BOOT_I2C_ADAP_COMPLETE(ihs0, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_0,
CONFIG_SYS_I2C_IHS_SLAVE_0, 0)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs0_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_0_1,
CONFIG_SYS_I2C_IHS_SLAVE_0_1, 16)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH1
U_BOOT_I2C_ADAP_COMPLETE(ihs1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_1,
CONFIG_SYS_I2C_IHS_SLAVE_1, 1)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs1_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_1_1,
CONFIG_SYS_I2C_IHS_SLAVE_1_1, 17)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH2
U_BOOT_I2C_ADAP_COMPLETE(ihs2, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_2,
CONFIG_SYS_I2C_IHS_SLAVE_2, 2)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs2_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_2_1,
CONFIG_SYS_I2C_IHS_SLAVE_2_1, 18)
#endif
#endif
#ifdef CONFIG_SYS_I2C_IHS_CH3
U_BOOT_I2C_ADAP_COMPLETE(ihs3, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_3,
CONFIG_SYS_I2C_IHS_SLAVE_3, 3)
#ifdef CONFIG_SYS_I2C_IHS_DUAL
U_BOOT_I2C_ADAP_COMPLETE(ihs3_1, ihs_i2c_init, ihs_i2c_probe,
ihs_i2c_read, ihs_i2c_write,
ihs_i2c_set_bus_speed,
CONFIG_SYS_I2C_IHS_SPEED_3_1,
CONFIG_SYS_I2C_IHS_SLAVE_3_1, 19)
#endif
#endif

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/pch.h>
int intel_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
return -ENOSYS;
}
int intel_i2c_probe_chip(struct udevice *bus, uint chip_addr, uint chip_flags)
{
return -ENOSYS;
}
int intel_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
return 0;
}
static int intel_i2c_probe(struct udevice *dev)
{
/*
* So far this is just setup code for ivybridge SMbus. When we have
* a full I2C driver this may need to be moved, generalised or made
* dependant on a particular compatible string.
*
* Set SMBus I/O base
*/
dm_pci_write_config32(dev, SMB_BASE,
SMBUS_IO_BASE | PCI_BASE_ADDRESS_SPACE_IO);
/* Set SMBus enable. */
dm_pci_write_config8(dev, HOSTC, HST_EN);
/* Set SMBus I/O space enable. */
dm_pci_write_config16(dev, PCI_COMMAND, PCI_COMMAND_IO);
/* Disable interrupt generation. */
outb(0, SMBUS_IO_BASE + SMBHSTCTL);
/* Clear any lingering errors, so transactions can run. */
outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
debug("SMBus controller enabled\n");
return 0;
}
static const struct dm_i2c_ops intel_i2c_ops = {
.xfer = intel_i2c_xfer,
.probe_chip = intel_i2c_probe_chip,
.set_bus_speed = intel_i2c_set_bus_speed,
};
static const struct udevice_id intel_i2c_ids[] = {
{ .compatible = "intel,ich-i2c" },
{ }
};
U_BOOT_DRIVER(intel_i2c) = {
.name = "i2c_intel",
.id = UCLASS_I2C,
.of_match = intel_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &intel_i2c_ops,
.probe = intel_i2c_probe,
};

View File

@@ -0,0 +1,730 @@
/*
* Copyright 2013 Broadcom Corporation.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/arch/sysmap.h>
#include <asm/kona-common/clk.h>
#include <i2c.h>
/* Hardware register offsets and field defintions */
#define CS_OFFSET 0x00000020
#define CS_ACK_SHIFT 3
#define CS_ACK_MASK 0x00000008
#define CS_ACK_CMD_GEN_START 0x00000000
#define CS_ACK_CMD_GEN_RESTART 0x00000001
#define CS_CMD_SHIFT 1
#define CS_CMD_CMD_NO_ACTION 0x00000000
#define CS_CMD_CMD_START_RESTART 0x00000001
#define CS_CMD_CMD_STOP 0x00000002
#define CS_EN_SHIFT 0
#define CS_EN_CMD_ENABLE_BSC 0x00000001
#define TIM_OFFSET 0x00000024
#define TIM_PRESCALE_SHIFT 6
#define TIM_P_SHIFT 3
#define TIM_NO_DIV_SHIFT 2
#define TIM_DIV_SHIFT 0
#define DAT_OFFSET 0x00000028
#define TOUT_OFFSET 0x0000002c
#define TXFCR_OFFSET 0x0000003c
#define TXFCR_FIFO_FLUSH_MASK 0x00000080
#define TXFCR_FIFO_EN_MASK 0x00000040
#define IER_OFFSET 0x00000044
#define IER_READ_COMPLETE_INT_MASK 0x00000010
#define IER_I2C_INT_EN_MASK 0x00000008
#define IER_FIFO_INT_EN_MASK 0x00000002
#define IER_NOACK_EN_MASK 0x00000001
#define ISR_OFFSET 0x00000048
#define ISR_RESERVED_MASK 0xffffff60
#define ISR_CMDBUSY_MASK 0x00000080
#define ISR_READ_COMPLETE_MASK 0x00000010
#define ISR_SES_DONE_MASK 0x00000008
#define ISR_ERR_MASK 0x00000004
#define ISR_TXFIFOEMPTY_MASK 0x00000002
#define ISR_NOACK_MASK 0x00000001
#define CLKEN_OFFSET 0x0000004c
#define CLKEN_AUTOSENSE_OFF_MASK 0x00000080
#define CLKEN_M_SHIFT 4
#define CLKEN_N_SHIFT 1
#define CLKEN_CLKEN_MASK 0x00000001
#define FIFO_STATUS_OFFSET 0x00000054
#define FIFO_STATUS_RXFIFO_EMPTY_MASK 0x00000004
#define FIFO_STATUS_TXFIFO_EMPTY_MASK 0x00000010
#define HSTIM_OFFSET 0x00000058
#define HSTIM_HS_MODE_MASK 0x00008000
#define HSTIM_HS_HOLD_SHIFT 10
#define HSTIM_HS_HIGH_PHASE_SHIFT 5
#define HSTIM_HS_SETUP_SHIFT 0
#define PADCTL_OFFSET 0x0000005c
#define PADCTL_PAD_OUT_EN_MASK 0x00000004
#define RXFCR_OFFSET 0x00000068
#define RXFCR_NACK_EN_SHIFT 7
#define RXFCR_READ_COUNT_SHIFT 0
#define RXFIFORDOUT_OFFSET 0x0000006c
/* Locally used constants */
#define MAX_RX_FIFO_SIZE 64U /* bytes */
#define MAX_TX_FIFO_SIZE 64U /* bytes */
#define I2C_TIMEOUT 100000 /* usecs */
#define WAIT_INT_CHK 100 /* usecs */
#if I2C_TIMEOUT % WAIT_INT_CHK
#error I2C_TIMEOUT must be a multiple of WAIT_INT_CHK
#endif
/* Operations that can be commanded to the controller */
enum bcm_kona_cmd_t {
BCM_CMD_NOACTION = 0,
BCM_CMD_START,
BCM_CMD_RESTART,
BCM_CMD_STOP,
};
enum bus_speed_index {
BCM_SPD_100K = 0,
BCM_SPD_400K,
BCM_SPD_1MHZ,
};
/* Internal divider settings for standard mode, fast mode and fast mode plus */
struct bus_speed_cfg {
uint8_t time_m; /* Number of cycles for setup time */
uint8_t time_n; /* Number of cycles for hold time */
uint8_t prescale; /* Prescale divider */
uint8_t time_p; /* Timing coefficient */
uint8_t no_div; /* Disable clock divider */
uint8_t time_div; /* Post-prescale divider */
};
static const struct bus_speed_cfg std_cfg_table[] = {
[BCM_SPD_100K] = {0x01, 0x01, 0x03, 0x06, 0x00, 0x02},
[BCM_SPD_400K] = {0x05, 0x01, 0x03, 0x05, 0x01, 0x02},
[BCM_SPD_1MHZ] = {0x01, 0x01, 0x03, 0x01, 0x01, 0x03},
};
struct bcm_kona_i2c_dev {
void *base;
uint speed;
const struct bus_speed_cfg *std_cfg;
};
/* Keep these two defines in sync */
#define DEF_SPD 100000
#define DEF_SPD_ENUM BCM_SPD_100K
#define DEF_DEVICE(num) \
{(void *)CONFIG_SYS_I2C_BASE##num, DEF_SPD, &std_cfg_table[DEF_SPD_ENUM]}
static struct bcm_kona_i2c_dev g_i2c_devs[CONFIG_SYS_MAX_I2C_BUS] = {
#ifdef CONFIG_SYS_I2C_BASE0
DEF_DEVICE(0),
#endif
#ifdef CONFIG_SYS_I2C_BASE1
DEF_DEVICE(1),
#endif
#ifdef CONFIG_SYS_I2C_BASE2
DEF_DEVICE(2),
#endif
#ifdef CONFIG_SYS_I2C_BASE3
DEF_DEVICE(3),
#endif
#ifdef CONFIG_SYS_I2C_BASE4
DEF_DEVICE(4),
#endif
#ifdef CONFIG_SYS_I2C_BASE5
DEF_DEVICE(5),
#endif
};
#define I2C_M_TEN 0x0010 /* ten bit address */
#define I2C_M_RD 0x0001 /* read data */
#define I2C_M_NOSTART 0x4000 /* no restart between msgs */
struct kona_i2c_msg {
uint16_t addr;
uint16_t flags;
uint16_t len;
uint8_t *buf;
};
static void bcm_kona_i2c_send_cmd_to_ctrl(struct bcm_kona_i2c_dev *dev,
enum bcm_kona_cmd_t cmd)
{
debug("%s, %d\n", __func__, cmd);
switch (cmd) {
case BCM_CMD_NOACTION:
writel((CS_CMD_CMD_NO_ACTION << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_START:
writel((CS_ACK_CMD_GEN_START << CS_ACK_SHIFT) |
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_RESTART:
writel((CS_ACK_CMD_GEN_RESTART << CS_ACK_SHIFT) |
(CS_CMD_CMD_START_RESTART << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
case BCM_CMD_STOP:
writel((CS_CMD_CMD_STOP << CS_CMD_SHIFT) |
(CS_EN_CMD_ENABLE_BSC << CS_EN_SHIFT),
dev->base + CS_OFFSET);
break;
default:
printf("Unknown command %d\n", cmd);
}
}
static void bcm_kona_i2c_enable_clock(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) | CLKEN_CLKEN_MASK,
dev->base + CLKEN_OFFSET);
}
static void bcm_kona_i2c_disable_clock(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_CLKEN_MASK,
dev->base + CLKEN_OFFSET);
}
/* Wait until at least one of the mask bit(s) are set */
static unsigned long wait_for_int_timeout(struct bcm_kona_i2c_dev *dev,
unsigned long time_left,
uint32_t mask)
{
uint32_t status;
while (time_left) {
status = readl(dev->base + ISR_OFFSET);
if ((status & ~ISR_RESERVED_MASK) == 0) {
debug("Bogus I2C interrupt 0x%x\n", status);
continue;
}
/* Must flush the TX FIFO when NAK detected */
if (status & ISR_NOACK_MASK)
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
dev->base + TXFCR_OFFSET);
writel(status & ~ISR_RESERVED_MASK, dev->base + ISR_OFFSET);
if (status & mask) {
/* We are done since one of the mask bits are set */
return time_left;
}
udelay(WAIT_INT_CHK);
time_left -= WAIT_INT_CHK;
}
return 0;
}
/* Send command to I2C bus */
static int bcm_kona_send_i2c_cmd(struct bcm_kona_i2c_dev *dev,
enum bcm_kona_cmd_t cmd)
{
int rc = 0;
unsigned long time_left = I2C_TIMEOUT;
/* Send the command */
bcm_kona_i2c_send_cmd_to_ctrl(dev, cmd);
/* Wait for transaction to finish or timeout */
time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
if (!time_left) {
printf("controller timed out\n");
rc = -ETIMEDOUT;
}
/* Clear command */
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
return rc;
}
/* Read a single RX FIFO worth of data from the i2c bus */
static int bcm_kona_i2c_read_fifo_single(struct bcm_kona_i2c_dev *dev,
uint8_t *buf, unsigned int len,
unsigned int last_byte_nak)
{
unsigned long time_left = I2C_TIMEOUT;
/* Start the RX FIFO */
writel((last_byte_nak << RXFCR_NACK_EN_SHIFT) |
(len << RXFCR_READ_COUNT_SHIFT), dev->base + RXFCR_OFFSET);
/* Wait for FIFO read to complete */
time_left =
wait_for_int_timeout(dev, time_left, IER_READ_COMPLETE_INT_MASK);
if (!time_left) {
printf("RX FIFO time out\n");
return -EREMOTEIO;
}
/* Read data from FIFO */
for (; len > 0; len--, buf++)
*buf = readl(dev->base + RXFIFORDOUT_OFFSET);
return 0;
}
/* Read any amount of data using the RX FIFO from the i2c bus */
static int bcm_kona_i2c_read_fifo(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned int bytes_to_read = MAX_RX_FIFO_SIZE;
unsigned int last_byte_nak = 0;
unsigned int bytes_read = 0;
int rc;
uint8_t *tmp_buf = msg->buf;
while (bytes_read < msg->len) {
if (msg->len - bytes_read <= MAX_RX_FIFO_SIZE) {
last_byte_nak = 1; /* NAK last byte of transfer */
bytes_to_read = msg->len - bytes_read;
}
rc = bcm_kona_i2c_read_fifo_single(dev, tmp_buf, bytes_to_read,
last_byte_nak);
if (rc < 0)
return -EREMOTEIO;
bytes_read += bytes_to_read;
tmp_buf += bytes_to_read;
}
return 0;
}
/* Write a single byte of data to the i2c bus */
static int bcm_kona_i2c_write_byte(struct bcm_kona_i2c_dev *dev, uint8_t data,
unsigned int nak_expected)
{
unsigned long time_left = I2C_TIMEOUT;
unsigned int nak_received;
/* Clear pending session done interrupt */
writel(ISR_SES_DONE_MASK, dev->base + ISR_OFFSET);
/* Send one byte of data */
writel(data, dev->base + DAT_OFFSET);
time_left = wait_for_int_timeout(dev, time_left, IER_I2C_INT_EN_MASK);
if (!time_left) {
debug("controller timed out\n");
return -ETIMEDOUT;
}
nak_received = readl(dev->base + CS_OFFSET) & CS_ACK_MASK ? 1 : 0;
if (nak_received ^ nak_expected) {
debug("unexpected NAK/ACK\n");
return -EREMOTEIO;
}
return 0;
}
/* Write a single TX FIFO worth of data to the i2c bus */
static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
uint8_t *buf, unsigned int len)
{
int k;
unsigned long time_left = I2C_TIMEOUT;
unsigned int fifo_status;
/* Write data into FIFO */
for (k = 0; k < len; k++)
writel(buf[k], (dev->base + DAT_OFFSET));
/* Wait for FIFO to empty */
do {
time_left =
wait_for_int_timeout(dev, time_left,
(IER_FIFO_INT_EN_MASK |
IER_NOACK_EN_MASK));
fifo_status = readl(dev->base + FIFO_STATUS_OFFSET);
} while (time_left && !(fifo_status & FIFO_STATUS_TXFIFO_EMPTY_MASK));
/* Check if there was a NAK */
if (readl(dev->base + CS_OFFSET) & CS_ACK_MASK) {
printf("unexpected NAK\n");
return -EREMOTEIO;
}
/* Check if a timeout occurred */
if (!time_left) {
printf("completion timed out\n");
return -EREMOTEIO;
}
return 0;
}
/* Write any amount of data using TX FIFO to the i2c bus */
static int bcm_kona_i2c_write_fifo(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned int bytes_to_write = MAX_TX_FIFO_SIZE;
unsigned int bytes_written = 0;
int rc;
uint8_t *tmp_buf = msg->buf;
while (bytes_written < msg->len) {
if (msg->len - bytes_written <= MAX_TX_FIFO_SIZE)
bytes_to_write = msg->len - bytes_written;
rc = bcm_kona_i2c_write_fifo_single(dev, tmp_buf,
bytes_to_write);
if (rc < 0)
return -EREMOTEIO;
bytes_written += bytes_to_write;
tmp_buf += bytes_to_write;
}
return 0;
}
/* Send i2c address */
static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg *msg)
{
unsigned char addr;
if (msg->flags & I2C_M_TEN) {
/* First byte is 11110XX0 where XX is upper 2 bits */
addr = 0xf0 | ((msg->addr & 0x300) >> 7);
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
/* Second byte is the remaining 8 bits */
addr = msg->addr & 0xff;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
if (msg->flags & I2C_M_RD) {
/* For read, send restart command */
if (bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART) < 0)
return -EREMOTEIO;
/* Then re-send the first byte with the read bit set */
addr = 0xf0 | ((msg->addr & 0x300) >> 7) | 0x01;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
}
} else {
addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;
}
return 0;
}
static void bcm_kona_i2c_enable_autosense(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + CLKEN_OFFSET) & ~CLKEN_AUTOSENSE_OFF_MASK,
dev->base + CLKEN_OFFSET);
}
static void bcm_kona_i2c_config_timing(struct bcm_kona_i2c_dev *dev)
{
writel(readl(dev->base + HSTIM_OFFSET) & ~HSTIM_HS_MODE_MASK,
dev->base + HSTIM_OFFSET);
writel((dev->std_cfg->prescale << TIM_PRESCALE_SHIFT) |
(dev->std_cfg->time_p << TIM_P_SHIFT) |
(dev->std_cfg->no_div << TIM_NO_DIV_SHIFT) |
(dev->std_cfg->time_div << TIM_DIV_SHIFT),
dev->base + TIM_OFFSET);
writel((dev->std_cfg->time_m << CLKEN_M_SHIFT) |
(dev->std_cfg->time_n << CLKEN_N_SHIFT) |
CLKEN_CLKEN_MASK, dev->base + CLKEN_OFFSET);
}
/* Master transfer function */
static int bcm_kona_i2c_xfer(struct bcm_kona_i2c_dev *dev,
struct kona_i2c_msg msgs[], int num)
{
struct kona_i2c_msg *pmsg;
int rc = 0;
int i;
/* Enable pad output */
writel(0, dev->base + PADCTL_OFFSET);
/* Enable internal clocks */
bcm_kona_i2c_enable_clock(dev);
/* Send start command */
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_START);
if (rc < 0) {
printf("Start command failed rc = %d\n", rc);
goto xfer_disable_pad;
}
/* Loop through all messages */
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
/* Send restart for subsequent messages */
if ((i != 0) && ((pmsg->flags & I2C_M_NOSTART) == 0)) {
rc = bcm_kona_send_i2c_cmd(dev, BCM_CMD_RESTART);
if (rc < 0) {
printf("restart cmd failed rc = %d\n", rc);
goto xfer_send_stop;
}
}
/* Send slave address */
if (!(pmsg->flags & I2C_M_NOSTART)) {
rc = bcm_kona_i2c_do_addr(dev, pmsg);
if (rc < 0) {
debug("NAK from addr %2.2x msg#%d rc = %d\n",
pmsg->addr, i, rc);
goto xfer_send_stop;
}
}
/* Perform data transfer */
if (pmsg->flags & I2C_M_RD) {
rc = bcm_kona_i2c_read_fifo(dev, pmsg);
if (rc < 0) {
printf("read failure\n");
goto xfer_send_stop;
}
} else {
rc = bcm_kona_i2c_write_fifo(dev, pmsg);
if (rc < 0) {
printf("write failure");
goto xfer_send_stop;
}
}
}
rc = num;
xfer_send_stop:
/* Send a STOP command */
bcm_kona_send_i2c_cmd(dev, BCM_CMD_STOP);
xfer_disable_pad:
/* Disable pad output */
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
/* Stop internal clock */
bcm_kona_i2c_disable_clock(dev);
return rc;
}
static uint bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev,
uint speed)
{
switch (speed) {
case 100000:
dev->std_cfg = &std_cfg_table[BCM_SPD_100K];
break;
case 400000:
dev->std_cfg = &std_cfg_table[BCM_SPD_400K];
break;
case 1000000:
dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ];
break;
default:
printf("%d hz bus speed not supported\n", speed);
return -EINVAL;
}
dev->speed = speed;
return 0;
}
static void bcm_kona_i2c_init(struct bcm_kona_i2c_dev *dev)
{
/* Parse bus speed */
bcm_kona_i2c_assign_bus_speed(dev, dev->speed);
/* Enable internal clocks */
bcm_kona_i2c_enable_clock(dev);
/* Configure internal dividers */
bcm_kona_i2c_config_timing(dev);
/* Disable timeout */
writel(0, dev->base + TOUT_OFFSET);
/* Enable autosense */
bcm_kona_i2c_enable_autosense(dev);
/* Enable TX FIFO */
writel(TXFCR_FIFO_FLUSH_MASK | TXFCR_FIFO_EN_MASK,
dev->base + TXFCR_OFFSET);
/* Mask all interrupts */
writel(0, dev->base + IER_OFFSET);
/* Clear all pending interrupts */
writel(ISR_CMDBUSY_MASK |
ISR_READ_COMPLETE_MASK |
ISR_SES_DONE_MASK |
ISR_ERR_MASK |
ISR_TXFIFOEMPTY_MASK | ISR_NOACK_MASK, dev->base + ISR_OFFSET);
/* Enable the controller but leave it idle */
bcm_kona_i2c_send_cmd_to_ctrl(dev, BCM_CMD_NOACTION);
/* Disable pad output */
writel(PADCTL_PAD_OUT_EN_MASK, dev->base + PADCTL_OFFSET);
}
/*
* uboot layer
*/
struct bcm_kona_i2c_dev *kona_get_dev(struct i2c_adapter *adap)
{
return &g_i2c_devs[adap->hwadapnr];
}
static void kona_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
if (clk_bsc_enable(dev->base))
return;
bcm_kona_i2c_init(dev);
}
static int kona_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
/* msg[0] writes the addr, msg[1] reads the data */
struct kona_i2c_msg msg[2];
unsigned char msgbuf0[64];
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
msg[0].addr = chip;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = msgbuf0; /* msgbuf0 contains incrementing reg addr */
msg[1].addr = chip;
msg[1].flags = I2C_M_RD;
/* msg[1].buf dest ptr increments each read */
msgbuf0[0] = (unsigned char)addr;
msg[1].buf = buffer;
msg[1].len = len;
if (bcm_kona_i2c_xfer(dev, msg, 2) < 0) {
/* Sending 2 i2c messages */
kona_i2c_init(adap, adap->speed, adap->slaveaddr);
debug("I2C read: I/O error\n");
return -EIO;
}
return 0;
}
static int kona_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
struct kona_i2c_msg msg[1];
unsigned char msgbuf0[64];
unsigned int i;
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
msg[0].addr = chip;
msg[0].flags = 0;
msg[0].len = 2; /* addr byte plus data */
msg[0].buf = msgbuf0;
for (i = 0; i < len; i++) {
msgbuf0[0] = addr++;
msgbuf0[1] = buffer[i];
if (bcm_kona_i2c_xfer(dev, msg, 1) < 0) {
kona_i2c_init(adap, adap->speed, adap->slaveaddr);
debug("I2C write: I/O error\n");
return -EIO;
}
}
return 0;
}
static int kona_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar tmp;
/*
* read addr 0x0 of the given chip.
*/
return kona_i2c_read(adap, chip, 0x0, 1, &tmp, 1);
}
static uint kona_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
struct bcm_kona_i2c_dev *dev = kona_get_dev(adap);
return bcm_kona_i2c_assign_bus_speed(dev, speed);
}
/*
* Register kona i2c adapters. Keep the order below so
* that the bus number matches the adapter number.
*/
#define DEF_ADAPTER(num) \
U_BOOT_I2C_ADAP_COMPLETE(kona##num, kona_i2c_init, kona_i2c_probe, \
kona_i2c_read, kona_i2c_write, \
kona_i2c_set_bus_speed, DEF_SPD, 0x00, num)
#ifdef CONFIG_SYS_I2C_BASE0
DEF_ADAPTER(0)
#endif
#ifdef CONFIG_SYS_I2C_BASE1
DEF_ADAPTER(1)
#endif
#ifdef CONFIG_SYS_I2C_BASE2
DEF_ADAPTER(2)
#endif
#ifdef CONFIG_SYS_I2C_BASE3
DEF_ADAPTER(3)
#endif
#ifdef CONFIG_SYS_I2C_BASE4
DEF_ADAPTER(4)
#endif
#ifdef CONFIG_SYS_I2C_BASE5
DEF_ADAPTER(5)
#endif

View File

@@ -0,0 +1,265 @@
/*
* LPC32xx I2C interface driver
*
* (C) Copyright 2014-2015 DENX Software Engineering GmbH
* Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/arch/clk.h>
/*
* Provide default speed and slave if target did not
*/
#if !defined(CONFIG_SYS_I2C_LPC32XX_SPEED)
#define CONFIG_SYS_I2C_LPC32XX_SPEED 350000
#endif
#if !defined(CONFIG_SYS_I2C_LPC32XX_SLAVE)
#define CONFIG_SYS_I2C_LPC32XX_SLAVE 0
#endif
/* i2c register set */
struct lpc32xx_i2c_registers {
union {
u32 rx;
u32 tx;
};
u32 stat;
u32 ctrl;
u32 clk_hi;
u32 clk_lo;
u32 adr;
u32 rxfl;
u32 txfl;
u32 rxb;
u32 txb;
u32 stx;
u32 stxfl;
};
/* TX register fields */
#define LPC32XX_I2C_TX_START 0x00000100
#define LPC32XX_I2C_TX_STOP 0x00000200
/* Control register values */
#define LPC32XX_I2C_SOFT_RESET 0x00000100
/* Status register values */
#define LPC32XX_I2C_STAT_TFF 0x00000400
#define LPC32XX_I2C_STAT_RFE 0x00000200
#define LPC32XX_I2C_STAT_DRMI 0x00000008
#define LPC32XX_I2C_STAT_NAI 0x00000004
#define LPC32XX_I2C_STAT_TDI 0x00000001
static struct lpc32xx_i2c_registers *lpc32xx_i2c[] = {
(struct lpc32xx_i2c_registers *)I2C1_BASE,
(struct lpc32xx_i2c_registers *)I2C2_BASE,
(struct lpc32xx_i2c_registers *)(USB_BASE + 0x300)
};
/* Set I2C bus speed */
static unsigned int lpc32xx_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
int half_period;
if (speed == 0)
return -EINVAL;
/* OTG I2C clock source and CLK registers are different */
if (adap->hwadapnr == 2) {
half_period = (get_periph_clk_rate() / speed) / 2;
if (half_period > 0xFF)
return -EINVAL;
} else {
half_period = (get_hclk_clk_rate() / speed) / 2;
if (half_period > 0x3FF)
return -EINVAL;
}
writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_hi);
writel(half_period, &lpc32xx_i2c[adap->hwadapnr]->clk_lo);
return 0;
}
/* I2C init called by cmd_i2c when doing 'i2c reset'. */
static void _i2c_init(struct i2c_adapter *adap,
int requested_speed, int slaveadd)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
/* soft reset (auto-clears) */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
/* set HI and LO periods for half of the default speed */
lpc32xx_i2c_set_bus_speed(adap, requested_speed);
}
/* I2C probe called by cmd_i2c when doing 'i2c probe'. */
static int lpc32xx_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* Addre slave for write with start before and stop after */
writel((dev<<1) | LPC32XX_I2C_TX_START | LPC32XX_I2C_TX_STOP,
&i2c->tx);
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* was there no acknowledge? */
return (stat & LPC32XX_I2C_STAT_NAI) ? -1 : 0;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*/
static int lpc32xx_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat, wlen;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write an address at all? */
if (alen) {
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
/* write address bytes */
while (alen--) {
/* compute address byte + stop for the last one */
int a = (addr >> (8 * alen)) & 0xff;
if (!alen)
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &i2c->tx);
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
}
/* do we have to read data at all? */
if (length) {
/* Address slave in read mode */
writel(1 | (dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
wlen = length;
/* get data */
while (length | wlen) {
/* read status for TFF and RFE */
stat = readl(&i2c->stat);
/* must we, can we write a trigger byte? */
if ((wlen > 0)
& (!(stat & LPC32XX_I2C_STAT_TFF))) {
wlen--;
/* write trigger byte + stop if last */
writel(wlen ? 0 :
LPC32XX_I2C_TX_STOP, &i2c->tx);
}
/* must we, can we read a data byte? */
if ((length > 0)
& (!(stat & LPC32XX_I2C_STAT_RFE))) {
length--;
/* read byte */
*(data++) = readl(&i2c->rx);
}
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
}
/* success */
return 0;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
static int lpc32xx_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
struct lpc32xx_i2c_registers *i2c = lpc32xx_i2c[adap->hwadapnr];
int stat;
/* Soft-reset the controller */
writel(LPC32XX_I2C_SOFT_RESET, &i2c->ctrl);
while (readl(&i2c->ctrl) & LPC32XX_I2C_SOFT_RESET)
;
/* do we need to write anything at all? */
if (alen | length)
/* Address slave in write mode */
writel((dev<<1) | LPC32XX_I2C_TX_START, &i2c->tx);
else
return 0;
/* write address bytes */
while (alen) {
/* wait for transmit fifo not full */
stat = readl(&i2c->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
alen--;
int a = (addr >> (8 * alen)) & 0xff;
if (!(alen | length))
a |= LPC32XX_I2C_TX_STOP;
/* Send address byte */
writel(a, &i2c->tx);
}
}
while (length) {
/* wait for transmit fifo not full */
stat = readl(&i2c->stat);
if (!(stat & LPC32XX_I2C_STAT_TFF)) {
/* compute data byte, add stop if length==0 */
length--;
int d = *(data++);
if (!length)
d |= LPC32XX_I2C_TX_STOP;
/* Send data byte */
writel(d, &i2c->tx);
}
}
/* wait for end of transation */
while (!((stat = readl(&i2c->stat)) & LPC32XX_I2C_STAT_TDI))
;
/* clear end-of-transaction flag */
writel(1, &i2c->stat);
return 0;
}
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_0, _i2c_init, lpc32xx_i2c_probe,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
0)
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_1, _i2c_init, lpc32xx_i2c_probe,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_LPC32XX_SPEED,
CONFIG_SYS_I2C_LPC32XX_SLAVE,
1)
U_BOOT_I2C_ADAP_COMPLETE(lpc32xx_2, _i2c_init, NULL,
lpc32xx_i2c_read, lpc32xx_i2c_write,
lpc32xx_i2c_set_bus_speed,
100000,
0,
2)

View File

@@ -0,0 +1,36 @@
config I2C_MUX
bool "Support I2C multiplexers"
depends on DM_I2C
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config SPL_I2C_MUX
bool "Support I2C multiplexers on SPL"
depends on I2C_MUX
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config I2C_ARB_GPIO_CHALLENGE
bool "GPIO-based I2C arbitration"
depends on I2C_MUX
help
If you say yes to this option, support will be included for an
I2C multimaster arbitration scheme using GPIOs and a challenge &
response mechanism where masters have to claim the bus by asserting
a GPIO.
config I2C_MUX_PCA954x
tristate "TI PCA954x I2C Mux/switches"
depends on I2C_MUX
help
If you say yes here you get support for the TI PCA954x
I2C mux/switch devices. It is x width I2C multiplexer which enables to
paritioning I2C bus and connect multiple devices with the same address
to the same I2C controller where driver handles proper routing to
target i2c device. PCA9544 and PCA9548 are supported.

View File

@@ -0,0 +1,8 @@
#
# Copyright (c) 2015 Google, Inc
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o
obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o

View File

@@ -0,0 +1,147 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
struct i2c_arbitrator_priv {
struct gpio_desc ap_claim;
struct gpio_desc ec_claim;
uint slew_delay_us;
uint wait_retry_ms;
uint wait_free_ms;
};
int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
ret = dm_gpio_set_value(&priv->ap_claim, 0);
udelay(priv->slew_delay_us);
return ret;
}
int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
unsigned start;
int ret;
debug("%s: %s\n", __func__, mux->name);
/* Start a round of trying to claim the bus */
start = get_timer(0);
do {
unsigned start_retry;
int waiting = 0;
/* Indicate that we want to claim the bus */
ret = dm_gpio_set_value(&priv->ap_claim, 1);
if (ret)
goto err;
udelay(priv->slew_delay_us);
/* Wait for the EC to release it */
start_retry = get_timer(0);
while (get_timer(start_retry) < priv->wait_retry_ms) {
ret = dm_gpio_get_value(&priv->ec_claim);
if (ret < 0) {
goto err;
} else if (!ret) {
/* We got it, so return */
return 0;
}
if (!waiting)
waiting = 1;
}
/* It didn't release, so give up, wait, and try again */
ret = dm_gpio_set_value(&priv->ap_claim, 0);
if (ret)
goto err;
mdelay(priv->wait_retry_ms);
} while (get_timer(start) < priv->wait_free_ms);
/* Give up, release our claim */
printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
ret = -ETIMEDOUT;
ret = 0;
err:
return ret;
}
static int i2c_arbitrator_probe(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
int ret;
debug("%s: %s\n", __func__, dev->name);
priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
1000;
priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
1000;
ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
GPIOD_IS_OUT);
if (ret)
goto err;
ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
GPIOD_IS_IN);
if (ret)
goto err_ec_gpio;
return 0;
err_ec_gpio:
dm_gpio_free(dev, &priv->ap_claim);
err:
debug("%s: ret=%d\n", __func__, ret);
return ret;
}
static int i2c_arbitrator_remove(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
dm_gpio_free(dev, &priv->ap_claim);
dm_gpio_free(dev, &priv->ec_claim);
return 0;
}
static const struct i2c_mux_ops i2c_arbitrator_ops = {
.select = i2c_arbitrator_select,
.deselect = i2c_arbitrator_deselect,
};
static const struct udevice_id i2c_arbitrator_ids[] = {
{ .compatible = "i2c-arb-gpio-challenge" },
{ }
};
U_BOOT_DRIVER(i2c_arbitrator) = {
.name = "i2c_arbitrator",
.id = UCLASS_I2C_MUX,
.of_match = i2c_arbitrator_ids,
.probe = i2c_arbitrator_probe,
.remove = i2c_arbitrator_remove,
.ops = &i2c_arbitrator_ops,
.priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
};

View File

@@ -0,0 +1,198 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <dm/lists.h>
#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct i2c_mux: Information the uclass stores about an I2C mux
*
* @selected: Currently selected mux, or -1 for none
* @i2c_bus: I2C bus to use for communcation
*/
struct i2c_mux {
int selected;
struct udevice *i2c_bus;
};
/**
* struct i2c_mux_bus: Information about each bus the mux controls
*
* @channel: Channel number used to select this bus
*/
struct i2c_mux_bus {
uint channel;
};
/* Find out the mux channel number */
static int i2c_mux_child_post_bind(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
int channel;
channel = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
if (channel < 0)
return -EINVAL;
plat->channel = channel;
return 0;
}
/* Find the I2C buses selected by this mux */
static int i2c_mux_post_bind(struct udevice *mux)
{
const void *blob = gd->fdt_blob;
int ret;
int offset;
debug("%s: %s\n", __func__, mux->name);
/*
* There is no compatible string in the sub-nodes, so we must manually
* bind these
*/
for (offset = fdt_first_subnode(blob, mux->of_offset);
offset > 0;
offset = fdt_next_subnode(blob, offset)) {
struct udevice *dev;
const char *name;
name = fdt_get_name(blob, offset, NULL);
ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name,
offset, &dev);
debug(" - bind ret=%d, %s\n", ret, dev ? dev->name : NULL);
if (ret)
return ret;
}
return 0;
}
/* Set up the mux ready for use */
static int i2c_mux_post_probe(struct udevice *mux)
{
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
priv->selected = -1;
ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
&priv->i2c_bus);
if (ret)
return ret;
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
return 0;
}
int i2c_mux_select(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->select)
return -ENOSYS;
return ops->select(mux, dev, plat->channel);
}
int i2c_mux_deselect(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->deselect)
return -ENOSYS;
return ops->deselect(mux, dev, plat->channel);
}
static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret, ret2;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
uint chip_flags)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->probe_chip)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->xfer)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static const struct dm_i2c_ops i2c_mux_bus_ops = {
.xfer = i2c_mux_bus_xfer,
.probe_chip = i2c_mux_bus_probe,
.set_bus_speed = i2c_mux_bus_set_bus_speed,
};
U_BOOT_DRIVER(i2c_mux_bus) = {
.name = "i2c_mux_bus_drv",
.id = UCLASS_I2C,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &i2c_mux_bus_ops,
};
UCLASS_DRIVER(i2c_mux) = {
.id = UCLASS_I2C_MUX,
.name = "i2c_mux",
.post_bind = i2c_mux_post_bind,
.post_probe = i2c_mux_post_probe,
.per_device_auto_alloc_size = sizeof(struct i2c_mux),
.per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
.child_post_bind = i2c_mux_child_post_bind,
};

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2015 - 2016 Xilinx, Inc.
* Written by Michal Simek
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
struct pca954x_priv {
u32 addr; /* I2C mux address */
u32 width; /* I2C mux width - number of busses */
};
static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
uchar byte = 0;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static int pca954x_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct pca954x_priv *priv = dev_get_priv(mux);
uchar byte = 1 << channel;
return dm_i2c_write(mux, priv->addr, &byte, 1);
}
static const struct i2c_mux_ops pca954x_ops = {
.select = pca954x_select,
.deselect = pca954x_deselect,
};
static const struct udevice_id pca954x_ids[] = {
{ .compatible = "nxp,pca9548", .data = (ulong)8 },
{ .compatible = "nxp,pca9544", .data = (ulong)4 },
{ }
};
static int pca954x_ofdata_to_platdata(struct udevice *dev)
{
struct pca954x_priv *priv = dev_get_priv(dev);
priv->addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", 0);
if (!priv->addr) {
debug("MUX not found\n");
return -ENODEV;
}
priv->width = dev_get_driver_data(dev);
if (!priv->width) {
debug("No I2C MUX width specified\n");
return -EINVAL;
}
debug("Device %s at 0x%x with width %d\n",
dev->name, priv->addr, priv->width);
return 0;
}
U_BOOT_DRIVER(pca954x) = {
.name = "pca954x",
.id = UCLASS_I2C_MUX,
.of_match = pca954x_ids,
.ops = &pca954x_ops,
.ofdata_to_platdata = pca954x_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct pca954x_priv),
};

471
u-boot/drivers/i2c/mv_i2c.c Normal file
View File

@@ -0,0 +1,471 @@
/*
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
*
* (C) Copyright 2003 Pengutronix e.K.
* Robert Schwebel <r.schwebel@pengutronix.de>
*
* (C) Copyright 2011 Marvell Inc.
* Lei Wen <leiwen@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
* Back ported to the 8xx platform (from the 8260 platform) by
* Murray.Jensen@cmst.csiro.au, 27-Jan-01.
*/
#include <common.h>
#include <asm/io.h>
#ifdef CONFIG_HARD_I2C
#include <i2c.h>
#include "mv_i2c.h"
#ifdef DEBUG_I2C
#define PRINTD(x) printf x
#else
#define PRINTD(x)
#endif
/* All transfers are described by this data structure */
struct mv_i2c_msg {
u8 condition;
u8 acknack;
u8 direction;
u8 data;
};
struct mv_i2c {
u32 ibmr;
u32 pad0;
u32 idbr;
u32 pad1;
u32 icr;
u32 pad2;
u32 isr;
u32 pad3;
u32 isar;
};
static struct mv_i2c *base;
static void i2c_board_init(struct mv_i2c *base)
{
#ifdef CONFIG_SYS_I2C_INIT_BOARD
u32 icr;
/*
* call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*
* disable I2C controller first, otherwhise it thinks we want to
* talk to the slave port...
*/
icr = readl(&base->icr);
writel(readl(&base->icr) & ~(ICR_SCLE | ICR_IUE), &base->icr);
i2c_init_board();
writel(icr, &base->icr);
#endif
}
#ifdef CONFIG_I2C_MULTI_BUS
static unsigned long i2c_regs[CONFIG_MV_I2C_NUM] = CONFIG_MV_I2C_REG;
static unsigned int bus_initialized[CONFIG_MV_I2C_NUM];
static unsigned int current_bus;
int i2c_set_bus_num(unsigned int bus)
{
if ((bus < 0) || (bus >= CONFIG_MV_I2C_NUM)) {
printf("Bad bus: %d\n", bus);
return -1;
}
base = (struct mv_i2c *)i2c_regs[bus];
current_bus = bus;
if (!bus_initialized[current_bus]) {
i2c_board_init(base);
bus_initialized[current_bus] = 1;
}
return 0;
}
unsigned int i2c_get_bus_num(void)
{
return current_bus;
}
#endif
/*
* i2c_reset: - reset the host controller
*
*/
static void i2c_reset(void)
{
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
writel(readl(&base->icr) | ICR_UR, &base->icr); /* reset the unit */
udelay(100);
writel(readl(&base->icr) & ~ICR_IUE, &base->icr); /* disable unit */
i2c_clk_enable();
writel(CONFIG_SYS_I2C_SLAVE, &base->isar); /* set our slave address */
writel(I2C_ICR_INIT, &base->icr); /* set control reg values */
writel(I2C_ISR_INIT, &base->isr); /* set clear interrupt bits */
writel(readl(&base->icr) | ICR_IUE, &base->icr); /* enable unit */
udelay(100);
}
/*
* i2c_isr_set_cleared: - wait until certain bits of the I2C status register
* are set and cleared
*
* @return: 1 in case of success, 0 means timeout (no match within 10 ms).
*/
static int i2c_isr_set_cleared(unsigned long set_mask,
unsigned long cleared_mask)
{
int timeout = 1000, isr;
do {
isr = readl(&base->isr);
udelay(10);
if (timeout-- < 0)
return 0;
} while (((isr & set_mask) != set_mask)
|| ((isr & cleared_mask) != 0));
return 1;
}
/*
* i2c_transfer: - Transfer one byte over the i2c bus
*
* This function can tranfer a byte over the i2c bus in both directions.
* It is used by the public API functions.
*
* @return: 0: transfer successful
* -1: message is empty
* -2: transmit timeout
* -3: ACK missing
* -4: receive timeout
* -5: illegal parameters
* -6: bus is busy and couldn't be aquired
*/
int i2c_transfer(struct mv_i2c_msg *msg)
{
int ret;
if (!msg)
goto transfer_error_msg_empty;
switch (msg->direction) {
case I2C_WRITE:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(0, ISR_IBB))
goto transfer_error_bus_busy;
/* start transmission */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
writel(msg->data, &base->idbr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* transmit register empty? */
if (!i2c_isr_set_cleared(ISR_ITE, 0))
goto transfer_error_transmit_timeout;
/* clear 'transmit empty' state */
writel(readl(&base->isr) | ISR_ITE, &base->isr);
/* wait for ACK from slave */
if (msg->acknack == I2C_ACKNAK_WAITACK)
if (!i2c_isr_set_cleared(0, ISR_ACKNAK))
goto transfer_error_ack_missing;
break;
case I2C_READ:
/* check if bus is not busy */
if (!i2c_isr_set_cleared(0, ISR_IBB))
goto transfer_error_bus_busy;
/* start receive */
writel(readl(&base->icr) & ~ICR_START, &base->icr);
writel(readl(&base->icr) & ~ICR_STOP, &base->icr);
if (msg->condition == I2C_COND_START)
writel(readl(&base->icr) | ICR_START, &base->icr);
if (msg->condition == I2C_COND_STOP)
writel(readl(&base->icr) | ICR_STOP, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDNAK)
writel(readl(&base->icr) | ICR_ACKNAK, &base->icr);
if (msg->acknack == I2C_ACKNAK_SENDACK)
writel(readl(&base->icr) & ~ICR_ACKNAK, &base->icr);
writel(readl(&base->icr) & ~ICR_ALDIE, &base->icr);
writel(readl(&base->icr) | ICR_TB, &base->icr);
/* receive register full? */
if (!i2c_isr_set_cleared(ISR_IRF, 0))
goto transfer_error_receive_timeout;
msg->data = readl(&base->idbr);
/* clear 'receive empty' state */
writel(readl(&base->isr) | ISR_IRF, &base->isr);
break;
default:
goto transfer_error_illegal_param;
}
return 0;
transfer_error_msg_empty:
PRINTD(("i2c_transfer: error: 'msg' is empty\n"));
ret = -1; goto i2c_transfer_finish;
transfer_error_transmit_timeout:
PRINTD(("i2c_transfer: error: transmit timeout\n"));
ret = -2; goto i2c_transfer_finish;
transfer_error_ack_missing:
PRINTD(("i2c_transfer: error: ACK missing\n"));
ret = -3; goto i2c_transfer_finish;
transfer_error_receive_timeout:
PRINTD(("i2c_transfer: error: receive timeout\n"));
ret = -4; goto i2c_transfer_finish;
transfer_error_illegal_param:
PRINTD(("i2c_transfer: error: illegal parameters\n"));
ret = -5; goto i2c_transfer_finish;
transfer_error_bus_busy:
PRINTD(("i2c_transfer: error: bus is busy\n"));
ret = -6; goto i2c_transfer_finish;
i2c_transfer_finish:
PRINTD(("i2c_transfer: ISR: 0x%04x\n", readl(&base->isr)));
i2c_reset();
return ret;
}
/* ------------------------------------------------------------------------ */
/* API Functions */
/* ------------------------------------------------------------------------ */
void i2c_init(int speed, int slaveaddr)
{
#ifdef CONFIG_I2C_MULTI_BUS
current_bus = 0;
base = (struct mv_i2c *)i2c_regs[current_bus];
#else
base = (struct mv_i2c *)CONFIG_MV_I2C_REG;
#endif
i2c_board_init(base);
}
/*
* i2c_probe: - Test if a chip answers for a given i2c address
*
* @chip: address of the chip which is searched for
* @return: 0 if a chip was found, -1 otherwhise
*/
int i2c_probe(uchar chip)
{
struct mv_i2c_msg msg;
i2c_reset();
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1) + 1;
if (i2c_transfer(&msg))
return -1;
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(&msg))
return -1;
return 0;
}
/*
* i2c_read: - Read multiple bytes from an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be read
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to write the data
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct mv_i2c_msg msg;
u8 addr_bytes[3]; /* lowest...highest byte of data address */
PRINTD(("i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, addr, alen, len));
i2c_reset();
/* dummy chip address write */
PRINTD(("i2c_read: dummy chip address write\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(&msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
/*addr &= ((1 << CONFIG_SYS_EEPROM_PAGE_WRITE_BITS)-1); */
addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF);
addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF);
addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF);
while (--alen >= 0) {
PRINTD(("i2c_read: send memory word address byte %1d\n", alen));
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr_bytes[alen];
if (i2c_transfer(&msg))
return -1;
}
/* start read sequence */
PRINTD(("i2c_read: start read sequence\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data |= 0x01;
if (i2c_transfer(&msg))
return -1;
/* read bytes; send NACK at last byte */
while (len--) {
if (len == 0) {
msg.condition = I2C_COND_STOP;
msg.acknack = I2C_ACKNAK_SENDNAK;
} else {
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_SENDACK;
}
msg.direction = I2C_READ;
msg.data = 0x00;
if (i2c_transfer(&msg))
return -1;
*buffer = msg.data;
PRINTD(("i2c_read: reading byte (0x%08x)=0x%02x\n",
(unsigned int)buffer, *buffer));
buffer++;
}
i2c_reset();
return 0;
}
/*
* i2c_write: - Write multiple bytes to an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be written
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to find the data to be written
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
struct mv_i2c_msg msg;
u8 addr_bytes[3]; /* lowest...highest byte of data address */
PRINTD(("i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, "
"len=0x%02x)\n", chip, addr, alen, len));
i2c_reset();
/* chip address write */
PRINTD(("i2c_write: chip address write\n"));
msg.condition = I2C_COND_START;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = (chip << 1);
msg.data &= 0xFE;
if (i2c_transfer(&msg))
return -1;
/*
* send memory address bytes;
* alen defines how much bytes we have to send.
*/
addr_bytes[0] = (u8)((addr >> 0) & 0x000000FF);
addr_bytes[1] = (u8)((addr >> 8) & 0x000000FF);
addr_bytes[2] = (u8)((addr >> 16) & 0x000000FF);
while (--alen >= 0) {
PRINTD(("i2c_write: send memory word address\n"));
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = addr_bytes[alen];
if (i2c_transfer(&msg))
return -1;
}
/* write bytes; send NACK at last byte */
while (len--) {
PRINTD(("i2c_write: writing byte (0x%08x)=0x%02x\n",
(unsigned int)buffer, *buffer));
if (len == 0)
msg.condition = I2C_COND_STOP;
else
msg.condition = I2C_COND_NORMAL;
msg.acknack = I2C_ACKNAK_WAITACK;
msg.direction = I2C_WRITE;
msg.data = *(buffer++);
if (i2c_transfer(&msg))
return -1;
}
i2c_reset();
return 0;
}
#endif /* CONFIG_HARD_I2C */

View File

@@ -0,0 +1,67 @@
/*
* (C) Copyright 2011
* Marvell Inc, <www.marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _MV_I2C_H_
#define _MV_I2C_H_
extern void i2c_clk_enable(void);
/* Shall the current transfer have a start/stop condition? */
#define I2C_COND_NORMAL 0
#define I2C_COND_START 1
#define I2C_COND_STOP 2
/* Shall the current transfer be ack/nacked or being waited for it? */
#define I2C_ACKNAK_WAITACK 1
#define I2C_ACKNAK_SENDACK 2
#define I2C_ACKNAK_SENDNAK 4
/* Specify who shall transfer the data (master or slave) */
#define I2C_READ 0
#define I2C_WRITE 1
#if (CONFIG_SYS_I2C_SPEED == 400000)
#define I2C_ICR_INIT (ICR_FM | ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD \
| ICR_SCLE)
#else
#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE)
#endif
#define I2C_ISR_INIT 0x7FF
/* ----- Control register bits ---------------------------------------- */
#define ICR_START 0x1 /* start bit */
#define ICR_STOP 0x2 /* stop bit */
#define ICR_ACKNAK 0x4 /* send ACK(0) or NAK(1) */
#define ICR_TB 0x8 /* transfer byte bit */
#define ICR_MA 0x10 /* master abort */
#define ICR_SCLE 0x20 /* master clock enable, mona SCLEA */
#define ICR_IUE 0x40 /* unit enable */
#define ICR_GCD 0x80 /* general call disable */
#define ICR_ITEIE 0x100 /* enable tx interrupts */
#define ICR_IRFIE 0x200 /* enable rx interrupts, mona: DRFIE */
#define ICR_BEIE 0x400 /* enable bus error ints */
#define ICR_SSDIE 0x800 /* slave STOP detected int enable */
#define ICR_ALDIE 0x1000 /* enable arbitration interrupt */
#define ICR_SADIE 0x2000 /* slave address detected int enable */
#define ICR_UR 0x4000 /* unit reset */
#define ICR_FM 0x8000 /* Fast Mode */
/* ----- Status register bits ----------------------------------------- */
#define ISR_RWM 0x1 /* read/write mode */
#define ISR_ACKNAK 0x2 /* ack/nak status */
#define ISR_UB 0x4 /* unit busy */
#define ISR_IBB 0x8 /* bus busy */
#define ISR_SSD 0x10 /* slave stop detected */
#define ISR_ALD 0x20 /* arbitration loss detected */
#define ISR_ITE 0x40 /* tx buffer empty */
#define ISR_IRF 0x80 /* rx buffer full */
#define ISR_GCAD 0x100 /* general call address detected */
#define ISR_SAD 0x200 /* slave address detected */
#define ISR_BED 0x400 /* bus error no ACK/NAK */
#endif

496
u-boot/drivers/i2c/mvtwsi.c Normal file
View File

@@ -0,0 +1,496 @@
/*
* Driver for the TWSI (i2c) controller found on the Marvell
* orion5x and kirkwood SoC families.
*
* Author: Albert Aribaud <albert.u.boot@aribaud.net>
* Copyright (c) 2010 Albert Aribaud.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/io.h>
/*
* include a file that will provide CONFIG_I2C_MVTWSI_BASE*
* and possibly other settings
*/
#if defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU))
#include <asm/arch/soc.h>
#elif defined(CONFIG_SUNXI)
#include <asm/arch/i2c.h>
#else
#error Driver mvtwsi not supported by SoC or board
#endif
/*
* TWSI register structure
*/
#ifdef CONFIG_SUNXI
struct mvtwsi_registers {
u32 slave_address;
u32 xtnd_slave_addr;
u32 data;
u32 control;
u32 status;
u32 baudrate;
u32 soft_reset;
};
#else
struct mvtwsi_registers {
u32 slave_address;
u32 data;
u32 control;
union {
u32 status; /* when reading */
u32 baudrate; /* when writing */
};
u32 xtnd_slave_addr;
u32 reserved[2];
u32 soft_reset;
};
#endif
/*
* Control register fields
*/
#define MVTWSI_CONTROL_ACK 0x00000004
#define MVTWSI_CONTROL_IFLG 0x00000008
#define MVTWSI_CONTROL_STOP 0x00000010
#define MVTWSI_CONTROL_START 0x00000020
#define MVTWSI_CONTROL_TWSIEN 0x00000040
#define MVTWSI_CONTROL_INTEN 0x00000080
/*
* On sun6i and newer IFLG is a write-clear bit which is cleared by writing 1,
* on other platforms it is a normal r/w bit which is cleared by writing 0.
*/
#ifdef CONFIG_SUNXI_GEN_SUN6I
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008
#else
#define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000
#endif
/*
* Status register values -- only those expected in normal master
* operation on non-10-bit-address devices; whatever status we don't
* expect in nominal conditions (bus errors, arbitration losses,
* missing ACKs...) we just pass back to the caller as an error
* code.
*/
#define MVTWSI_STATUS_START 0x08
#define MVTWSI_STATUS_REPEATED_START 0x10
#define MVTWSI_STATUS_ADDR_W_ACK 0x18
#define MVTWSI_STATUS_DATA_W_ACK 0x28
#define MVTWSI_STATUS_ADDR_R_ACK 0x40
#define MVTWSI_STATUS_ADDR_R_NAK 0x48
#define MVTWSI_STATUS_DATA_R_ACK 0x50
#define MVTWSI_STATUS_DATA_R_NAK 0x58
#define MVTWSI_STATUS_IDLE 0xF8
/*
* MVTWSI controller base
*/
static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
#ifdef CONFIG_I2C_MVTWSI_BASE0
case 0:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE0;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE1
case 1:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE1;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE2
case 2:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE2;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE3
case 3:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE3;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE4
case 4:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE4;
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE5
case 5:
return (struct mvtwsi_registers *) CONFIG_I2C_MVTWSI_BASE5;
#endif
default:
printf("Missing mvtwsi controller %d base\n", adap->hwadapnr);
break;
}
return NULL;
}
/*
* Returned statuses are 0 for success and nonzero otherwise.
* Currently, cmd_i2c and cmd_eeprom do not interpret an error status.
* Thus to ease debugging, the return status contains some debug info:
* - bits 31..24 are error class: 1 is timeout, 2 is 'status mismatch'.
* - bits 23..16 are the last value of the control register.
* - bits 15..8 are the last value of the status register.
* - bits 7..0 are the expected value of the status register.
*/
#define MVTWSI_ERROR_WRONG_STATUS 0x01
#define MVTWSI_ERROR_TIMEOUT 0x02
#define MVTWSI_ERROR(ec, lc, ls, es) (((ec << 24) & 0xFF000000) | \
((lc << 16) & 0x00FF0000) | ((ls<<8) & 0x0000FF00) | (es & 0xFF))
/*
* Wait for IFLG to raise, or return 'timeout'; then if status is as expected,
* return 0 (ok) or return 'wrong status'.
*/
static int twsi_wait(struct i2c_adapter *adap, int expected_status)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
int control, status;
int timeout = 1000;
do {
control = readl(&twsi->control);
if (control & MVTWSI_CONTROL_IFLG) {
status = readl(&twsi->status);
if (status == expected_status)
return 0;
else
return MVTWSI_ERROR(
MVTWSI_ERROR_WRONG_STATUS,
control, status, expected_status);
}
udelay(10); /* one clock cycle at 100 kHz */
} while (timeout--);
status = readl(&twsi->status);
return MVTWSI_ERROR(
MVTWSI_ERROR_TIMEOUT, control, status, expected_status);
}
/*
* Assert the START condition, either in a single I2C transaction
* or inside back-to-back ones (repeated starts).
*/
static int twsi_start(struct i2c_adapter *adap, int expected_status, u8 *flags)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
/* globally set TWSIEN in case it was not */
*flags |= MVTWSI_CONTROL_TWSIEN;
/* assert START */
writel(*flags | MVTWSI_CONTROL_START |
MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* wait for controller to process START */
return twsi_wait(adap, expected_status);
}
/*
* Send a byte (i2c address or data).
*/
static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status,
u8 *flags)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
/* put byte in data register for sending */
writel(byte, &twsi->data);
/* clear any pending interrupt -- that'll cause sending */
writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* wait for controller to receive byte and check ACK */
return twsi_wait(adap, expected_status);
}
/*
* Receive a byte.
* Global mvtwsi_control_flags variable says if we should ack or nak.
*/
static int twsi_recv(struct i2c_adapter *adap, u8 *byte, u8 *flags)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
int expected_status, status;
/* compute expected status based on ACK bit in global control flags */
if (*flags & MVTWSI_CONTROL_ACK)
expected_status = MVTWSI_STATUS_DATA_R_ACK;
else
expected_status = MVTWSI_STATUS_DATA_R_NAK;
/* acknowledge *previous state* and launch receive */
writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* wait for controller to receive byte and assert ACK or NAK */
status = twsi_wait(adap, expected_status);
/* if we did receive expected byte then store it */
if (status == 0)
*byte = readl(&twsi->data);
/* return status */
return status;
}
/*
* Assert the STOP condition.
* This is also used to force the bus back in idle (SDA=SCL=1).
*/
static int twsi_stop(struct i2c_adapter *adap, int status)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
int control, stop_status;
int timeout = 1000;
/* assert STOP */
control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP;
writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
/* wait for IDLE; IFLG won't rise so twsi_wait() is no use. */
do {
stop_status = readl(&twsi->status);
if (stop_status == MVTWSI_STATUS_IDLE)
break;
udelay(10); /* one clock cycle at 100 kHz */
} while (timeout--);
control = readl(&twsi->control);
if (stop_status != MVTWSI_STATUS_IDLE)
if (status == 0)
status = MVTWSI_ERROR(
MVTWSI_ERROR_TIMEOUT,
control, status, MVTWSI_STATUS_IDLE);
return status;
}
static unsigned int twsi_calc_freq(const int n, const int m)
{
#ifdef CONFIG_SUNXI
return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n));
#else
return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
#endif
}
/*
* Reset controller.
* Controller reset also resets the baud rate and slave address, so
* they must be re-established afterwards.
*/
static void twsi_reset(struct i2c_adapter *adap)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
/* reset controller */
writel(0, &twsi->soft_reset);
/* wait 2 ms -- this is what the Marvell LSP does */
udelay(20000);
}
/*
* I2C init called by cmd_i2c when doing 'i2c reset'.
* Sets baud to the highest possible value not exceeding requested one.
*/
static unsigned int twsi_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int requested_speed)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
unsigned int tmp_speed, highest_speed, n, m;
unsigned int baud = 0x44; /* baudrate at controller reset */
/* use actual speed to collect progressively higher values */
highest_speed = 0;
/* compute m, n setting for highest speed not above requested speed */
for (n = 0; n < 8; n++) {
for (m = 0; m < 16; m++) {
tmp_speed = twsi_calc_freq(n, m);
if ((tmp_speed <= requested_speed)
&& (tmp_speed > highest_speed)) {
highest_speed = tmp_speed;
baud = (m << 3) | n;
}
}
}
writel(baud, &twsi->baudrate);
return 0;
}
static void twsi_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct mvtwsi_registers *twsi = twsi_get_base(adap);
/* reset controller */
twsi_reset(adap);
/* set speed */
twsi_i2c_set_bus_speed(adap, speed);
/* set slave address even though we don't use it */
writel(slaveadd, &twsi->slave_address);
writel(0, &twsi->xtnd_slave_addr);
/* assert STOP but don't care for the result */
(void) twsi_stop(adap, 0);
}
/*
* Begin I2C transaction with expected start status, at given address.
* Common to i2c_probe, i2c_read and i2c_write.
* Expected address status will derive from direction bit (bit 0) in addr.
*/
static int i2c_begin(struct i2c_adapter *adap, int expected_start_status,
u8 addr, u8 *flags)
{
int status, expected_addr_status;
/* compute expected address status from direction bit in addr */
if (addr & 1) /* reading */
expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK;
else /* writing */
expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
/* assert START */
status = twsi_start(adap, expected_start_status, flags);
/* send out the address if the start went well */
if (status == 0)
status = twsi_send(adap, addr, expected_addr_status,
flags);
/* return ok or status of first failure to caller */
return status;
}
/*
* I2C probe called by cmd_i2c when doing 'i2c probe'.
* Begin read, nak data byte, end.
*/
static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
u8 dummy_byte;
u8 flags = 0;
int status;
/* begin i2c read */
status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1) | 1, &flags);
/* dummy read was accepted: receive byte but NAK it. */
if (status == 0)
status = twsi_recv(adap, &dummy_byte, &flags);
/* Stop transaction */
twsi_stop(adap, 0);
/* return 0 or status of first failure */
return status;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*
* NOTE: some EEPROMS want a stop right before the second start, while
* some will choke if it is there. Deciding which we should do is eeprom
* stuff, not i2c, but at the moment the APIs won't let us put it in
* cmd_eeprom, so we have to choose here, and for the moment that'll be
* a repeated start without a preceding stop.
*/
static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *data, int length)
{
int status;
u8 flags = 0;
/* begin i2c write to send the address bytes */
status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
/* send addr bytes */
while ((status == 0) && alen--)
status = twsi_send(adap, addr >> (8*alen),
MVTWSI_STATUS_DATA_W_ACK, &flags);
/* begin i2c read to receive eeprom data bytes */
if (status == 0)
status = i2c_begin(adap, MVTWSI_STATUS_REPEATED_START,
(chip << 1) | 1, &flags);
/* prepare ACK if at least one byte must be received */
if (length > 0)
flags |= MVTWSI_CONTROL_ACK;
/* now receive actual bytes */
while ((status == 0) && length--) {
/* reset NAK if we if no more to read now */
if (length == 0)
flags &= ~MVTWSI_CONTROL_ACK;
/* read current byte */
status = twsi_recv(adap, data++, &flags);
}
/* Stop transaction */
status = twsi_stop(adap, status);
/* return 0 or status of first failure */
return status;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *data, int length)
{
int status;
u8 flags = 0;
/* begin i2c write to send the eeprom adress bytes then data bytes */
status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
/* send addr bytes */
while ((status == 0) && alen--)
status = twsi_send(adap, addr >> (8*alen),
MVTWSI_STATUS_DATA_W_ACK, &flags);
/* send data bytes */
while ((status == 0) && (length-- > 0))
status = twsi_send(adap, *(data++), MVTWSI_STATUS_DATA_W_ACK,
&flags);
/* Stop transaction */
status = twsi_stop(adap, status);
/* return 0 or status of first failure */
return status;
}
#ifdef CONFIG_I2C_MVTWSI_BASE0
U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE1
U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE2
U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE3
U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE4
U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4)
#endif
#ifdef CONFIG_I2C_MVTWSI_BASE5
U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe,
twsi_i2c_read, twsi_i2c_write,
twsi_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5)
#endif

View File

@@ -0,0 +1,903 @@
/*
* i2c driver for Freescale i.MX series
*
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
* (c) 2011 Marek Vasut <marek.vasut@gmail.com>
*
* Based on i2c-imx.c from linux kernel:
* Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de>
* Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de>
* Copyright (C) 2007 RightHand Technologies, Inc.
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
*
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/errno.h>
#include <asm/imx-common/mxc_i2c.h>
#include <asm/io.h>
#include <i2c.h>
#include <watchdog.h>
#include <dm.h>
#include <dm/pinctrl.h>
#include <fdtdec.h>
DECLARE_GLOBAL_DATA_PTR;
#define I2C_QUIRK_FLAG (1 << 0)
#define IMX_I2C_REGSHIFT 2
#define VF610_I2C_REGSHIFT 0
#define I2C_EARLY_INIT_INDEX 0
#ifdef CONFIG_SYS_I2C_IFDR_DIV
#define I2C_IFDR_DIV_CONSERVATIVE CONFIG_SYS_I2C_IFDR_DIV
#else
#define I2C_IFDR_DIV_CONSERVATIVE 0x7e
#endif
/* Register index */
#define IADR 0
#define IFDR 1
#define I2CR 2
#define I2SR 3
#define I2DR 4
#define I2CR_IIEN (1 << 6)
#define I2CR_MSTA (1 << 5)
#define I2CR_MTX (1 << 4)
#define I2CR_TX_NO_AK (1 << 3)
#define I2CR_RSTA (1 << 2)
#define I2SR_ICF (1 << 7)
#define I2SR_IBB (1 << 5)
#define I2SR_IAL (1 << 4)
#define I2SR_IIF (1 << 1)
#define I2SR_RX_NO_AK (1 << 0)
#ifdef I2C_QUIRK_REG
#define I2CR_IEN (0 << 7)
#define I2CR_IDIS (1 << 7)
#define I2SR_IIF_CLEAR (1 << 1)
#else
#define I2CR_IEN (1 << 7)
#define I2CR_IDIS (0 << 7)
#define I2SR_IIF_CLEAR (0 << 1)
#endif
#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE)
#error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
#endif
#ifdef I2C_QUIRK_REG
static u16 i2c_clk_div[60][2] = {
{ 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
{ 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
{ 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
{ 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
{ 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
{ 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
{ 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
{ 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
{ 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
{ 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
{ 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
{ 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
{ 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
{ 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
{ 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
};
#else
static u16 i2c_clk_div[50][2] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
{ 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
{ 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
{ 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
{ 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
{ 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
{ 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
{ 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
{ 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
{ 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};
#endif
#ifndef CONFIG_SYS_MXC_I2C1_SPEED
#define CONFIG_SYS_MXC_I2C1_SPEED 100000
#endif
#ifndef CONFIG_SYS_MXC_I2C2_SPEED
#define CONFIG_SYS_MXC_I2C2_SPEED 100000
#endif
#ifndef CONFIG_SYS_MXC_I2C3_SPEED
#define CONFIG_SYS_MXC_I2C3_SPEED 100000
#endif
#ifndef CONFIG_SYS_MXC_I2C4_SPEED
#define CONFIG_SYS_MXC_I2C4_SPEED 100000
#endif
#ifndef CONFIG_SYS_MXC_I2C1_SLAVE
#define CONFIG_SYS_MXC_I2C1_SLAVE 0
#endif
#ifndef CONFIG_SYS_MXC_I2C2_SLAVE
#define CONFIG_SYS_MXC_I2C2_SLAVE 0
#endif
#ifndef CONFIG_SYS_MXC_I2C3_SLAVE
#define CONFIG_SYS_MXC_I2C3_SLAVE 0
#endif
#ifndef CONFIG_SYS_MXC_I2C4_SLAVE
#define CONFIG_SYS_MXC_I2C4_SLAVE 0
#endif
/*
* Calculate and set proper clock divider
*/
static uint8_t i2c_imx_get_clk(struct mxc_i2c_bus *i2c_bus, unsigned int rate)
{
unsigned int i2c_clk_rate;
unsigned int div;
u8 clk_div;
#if defined(CONFIG_MX31)
struct clock_control_regs *sc_regs =
(struct clock_control_regs *)CCM_BASE;
/* start the required I2C clock */
writel(readl(&sc_regs->cgr0) | (3 << CONFIG_SYS_I2C_CLK_OFFSET),
&sc_regs->cgr0);
#endif
/* Divider value calculation */
i2c_clk_rate = mxc_get_clock(MXC_I2C_CLK);
div = (i2c_clk_rate + rate - 1) / rate;
if (div < i2c_clk_div[0][0])
clk_div = 0;
else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
clk_div = ARRAY_SIZE(i2c_clk_div) - 1;
else
for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++)
;
/* Store divider value */
return clk_div;
}
/*
* Set I2C Bus speed
*/
static int bus_i2c_set_bus_speed(struct mxc_i2c_bus *i2c_bus, int speed)
{
ulong base = i2c_bus->base;
bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
u8 clk_idx = i2c_imx_get_clk(i2c_bus, speed);
u8 idx = i2c_clk_div[clk_idx][1];
int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
if (!base)
return -ENODEV;
/* Store divider value */
writeb(idx, base + (IFDR << reg_shift));
/* Reset module */
writeb(I2CR_IDIS, base + (I2CR << reg_shift));
writeb(0, base + (I2SR << reg_shift));
return 0;
}
#define ST_BUS_IDLE (0 | (I2SR_IBB << 8))
#define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8))
#define ST_IIF (I2SR_IIF | (I2SR_IIF << 8))
static int wait_for_sr_state(struct mxc_i2c_bus *i2c_bus, unsigned state)
{
unsigned sr;
ulong elapsed;
bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
ulong base = i2c_bus->base;
ulong start_time = get_timer(0);
for (;;) {
sr = readb(base + (I2SR << reg_shift));
if (sr & I2SR_IAL) {
if (quirk)
writeb(sr | I2SR_IAL, base +
(I2SR << reg_shift));
else
writeb(sr & ~I2SR_IAL, base +
(I2SR << reg_shift));
printf("%s: Arbitration lost sr=%x cr=%x state=%x\n",
__func__, sr, readb(base + (I2CR << reg_shift)),
state);
return -ERESTART;
}
if ((sr & (state >> 8)) == (unsigned char)state)
return sr;
WATCHDOG_RESET();
elapsed = get_timer(start_time);
if (elapsed > (CONFIG_SYS_HZ / 10)) /* .1 seconds */
break;
}
printf("%s: failed sr=%x cr=%x state=%x\n", __func__,
sr, readb(base + (I2CR << reg_shift)), state);
return -ETIMEDOUT;
}
static int tx_byte(struct mxc_i2c_bus *i2c_bus, u8 byte)
{
int ret;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
ulong base = i2c_bus->base;
writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
writeb(byte, base + (I2DR << reg_shift));
ret = wait_for_sr_state(i2c_bus, ST_IIF);
if (ret < 0)
return ret;
if (ret & I2SR_RX_NO_AK)
return -ENODEV;
return 0;
}
/*
* Stub implementations for outer i2c slave operations.
*/
void __i2c_force_reset_slave(void)
{
}
void i2c_force_reset_slave(void)
__attribute__((weak, alias("__i2c_force_reset_slave")));
/*
* Stop I2C transaction
*/
static void i2c_imx_stop(struct mxc_i2c_bus *i2c_bus)
{
int ret;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
ulong base = i2c_bus->base;
unsigned int temp = readb(base + (I2CR << reg_shift));
temp &= ~(I2CR_MSTA | I2CR_MTX);
writeb(temp, base + (I2CR << reg_shift));
ret = wait_for_sr_state(i2c_bus, ST_BUS_IDLE);
if (ret < 0)
printf("%s:trigger stop failed\n", __func__);
}
/*
* Send start signal, chip address and
* write register address
*/
static int i2c_init_transfer_(struct mxc_i2c_bus *i2c_bus, u8 chip,
u32 addr, int alen)
{
unsigned int temp;
int ret;
bool quirk = i2c_bus->driver_data & I2C_QUIRK_FLAG ? true : false;
ulong base = i2c_bus->base;
int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
/* Reset i2c slave */
i2c_force_reset_slave();
/* Enable I2C controller */
if (quirk)
ret = readb(base + (I2CR << reg_shift)) & I2CR_IDIS;
else
ret = !(readb(base + (I2CR << reg_shift)) & I2CR_IEN);
if (ret) {
writeb(I2CR_IEN, base + (I2CR << reg_shift));
/* Wait for controller to be stable */
udelay(50);
}
if (readb(base + (IADR << reg_shift)) == (chip << 1))
writeb((chip << 1) ^ 2, base + (IADR << reg_shift));
writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
ret = wait_for_sr_state(i2c_bus, ST_BUS_IDLE);
if (ret < 0)
return ret;
/* Start I2C transaction */
temp = readb(base + (I2CR << reg_shift));
temp |= I2CR_MSTA;
writeb(temp, base + (I2CR << reg_shift));
ret = wait_for_sr_state(i2c_bus, ST_BUS_BUSY);
if (ret < 0)
return ret;
temp |= I2CR_MTX | I2CR_TX_NO_AK;
writeb(temp, base + (I2CR << reg_shift));
/* write slave address */
ret = tx_byte(i2c_bus, chip << 1);
if (ret < 0)
return ret;
while (alen--) {
ret = tx_byte(i2c_bus, (addr >> (alen * 8)) & 0xff);
if (ret < 0)
return ret;
}
return 0;
}
#ifndef CONFIG_DM_I2C
int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
{
if (i2c_bus && i2c_bus->idle_bus_fn)
return i2c_bus->idle_bus_fn(i2c_bus->idle_bus_data);
return 0;
}
#else
/*
* See Linux Documentation/devicetree/bindings/i2c/i2c-imx.txt
* "
* scl-gpios: specify the gpio related to SCL pin
* sda-gpios: specify the gpio related to SDA pin
* add pinctrl to configure i2c pins to gpio function for i2c
* bus recovery, call it "gpio" state
* "
*
* The i2c_idle_bus is an implementation following Linux Kernel.
*/
int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus)
{
struct udevice *bus = i2c_bus->bus;
struct gpio_desc *scl_gpio = &i2c_bus->scl_gpio;
struct gpio_desc *sda_gpio = &i2c_bus->sda_gpio;
int sda, scl;
int i, ret = 0;
ulong elapsed, start_time;
if (pinctrl_select_state(bus, "gpio")) {
dev_dbg(bus, "Can not to switch to use gpio pinmux\n");
/*
* GPIO pinctrl for i2c force idle is not a must,
* but it is strongly recommended to be used.
* Because it can help you to recover from bad
* i2c bus state. Do not return failure, because
* it is not a must.
*/
return 0;
}
dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
dm_gpio_set_dir_flags(sda_gpio, GPIOD_IS_IN);
scl = dm_gpio_get_value(scl_gpio);
sda = dm_gpio_get_value(sda_gpio);
if ((sda & scl) == 1)
goto exit; /* Bus is idle already */
/* Send high and low on the SCL line */
for (i = 0; i < 9; i++) {
dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_OUT);
dm_gpio_set_value(scl_gpio, 0);
udelay(50);
dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
udelay(50);
}
start_time = get_timer(0);
for (;;) {
dm_gpio_set_dir_flags(scl_gpio, GPIOD_IS_IN);
dm_gpio_set_dir_flags(sda_gpio, GPIOD_IS_IN);
scl = dm_gpio_get_value(scl_gpio);
sda = dm_gpio_get_value(sda_gpio);
if ((sda & scl) == 1)
break;
WATCHDOG_RESET();
elapsed = get_timer(start_time);
if (elapsed > (CONFIG_SYS_HZ / 5)) { /* .2 seconds */
ret = -EBUSY;
printf("%s: failed to clear bus, sda=%d scl=%d\n", __func__, sda, scl);
break;
}
}
exit:
pinctrl_select_state(bus, "default");
return ret;
}
#endif
static int i2c_init_transfer(struct mxc_i2c_bus *i2c_bus, u8 chip,
u32 addr, int alen)
{
int retry;
int ret;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
if (!i2c_bus->base)
return -ENODEV;
for (retry = 0; retry < 3; retry++) {
ret = i2c_init_transfer_(i2c_bus, chip, addr, alen);
if (ret >= 0)
return 0;
i2c_imx_stop(i2c_bus);
if (ret == -ENODEV)
return ret;
printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip,
retry);
if (ret != -ERESTART)
/* Disable controller */
writeb(I2CR_IDIS, i2c_bus->base + (I2CR << reg_shift));
udelay(100);
if (i2c_idle_bus(i2c_bus) < 0)
break;
}
printf("%s: give up i2c_regs=0x%lx\n", __func__, i2c_bus->base);
return ret;
}
static int i2c_write_data(struct mxc_i2c_bus *i2c_bus, u8 chip, const u8 *buf,
int len)
{
int i, ret = 0;
debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
debug("write_data: ");
/* use rc for counter */
for (i = 0; i < len; ++i)
debug(" 0x%02x", buf[i]);
debug("\n");
for (i = 0; i < len; i++) {
ret = tx_byte(i2c_bus, buf[i]);
if (ret < 0) {
debug("i2c_write_data(): rc=%d\n", ret);
break;
}
}
return ret;
}
static int i2c_read_data(struct mxc_i2c_bus *i2c_bus, uchar chip, uchar *buf,
int len)
{
int ret;
unsigned int temp;
int i;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
ulong base = i2c_bus->base;
debug("i2c_read_data: chip=0x%x, len=0x%x\n", chip, len);
/* setup bus to read data */
temp = readb(base + (I2CR << reg_shift));
temp &= ~(I2CR_MTX | I2CR_TX_NO_AK);
if (len == 1)
temp |= I2CR_TX_NO_AK;
writeb(temp, base + (I2CR << reg_shift));
writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
/* dummy read to clear ICF */
readb(base + (I2DR << reg_shift));
/* read data */
for (i = 0; i < len; i++) {
ret = wait_for_sr_state(i2c_bus, ST_IIF);
if (ret < 0) {
debug("i2c_read_data(): ret=%d\n", ret);
i2c_imx_stop(i2c_bus);
return ret;
}
/*
* It must generate STOP before read I2DR to prevent
* controller from generating another clock cycle
*/
if (i == (len - 1)) {
i2c_imx_stop(i2c_bus);
} else if (i == (len - 2)) {
temp = readb(base + (I2CR << reg_shift));
temp |= I2CR_TX_NO_AK;
writeb(temp, base + (I2CR << reg_shift));
}
writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift));
buf[i] = readb(base + (I2DR << reg_shift));
}
/* reuse ret for counter*/
for (ret = 0; ret < len; ++ret)
debug(" 0x%02x", buf[ret]);
debug("\n");
i2c_imx_stop(i2c_bus);
return 0;
}
#ifndef CONFIG_DM_I2C
/*
* Read data from I2C device
*/
static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
int alen, u8 *buf, int len)
{
int ret = 0;
u32 temp;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
ulong base = i2c_bus->base;
ret = i2c_init_transfer(i2c_bus, chip, addr, alen);
if (ret < 0)
return ret;
temp = readb(base + (I2CR << reg_shift));
temp |= I2CR_RSTA;
writeb(temp, base + (I2CR << reg_shift));
ret = tx_byte(i2c_bus, (chip << 1) | 1);
if (ret < 0) {
i2c_imx_stop(i2c_bus);
return ret;
}
ret = i2c_read_data(i2c_bus, chip, buf, len);
i2c_imx_stop(i2c_bus);
return ret;
}
/*
* Write data to I2C device
*/
static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr,
int alen, const u8 *buf, int len)
{
int ret = 0;
ret = i2c_init_transfer(i2c_bus, chip, addr, alen);
if (ret < 0)
return ret;
ret = i2c_write_data(i2c_bus, chip, buf, len);
i2c_imx_stop(i2c_bus);
return ret;
}
#if !defined(I2C2_BASE_ADDR)
#define I2C2_BASE_ADDR 0
#endif
#if !defined(I2C3_BASE_ADDR)
#define I2C3_BASE_ADDR 0
#endif
#if !defined(I2C4_BASE_ADDR)
#define I2C4_BASE_ADDR 0
#endif
static struct mxc_i2c_bus mxc_i2c_buses[] = {
#if defined(CONFIG_LS102XA) || defined(CONFIG_VF610) || \
defined(CONFIG_FSL_LAYERSCAPE)
{ 0, I2C1_BASE_ADDR, I2C_QUIRK_FLAG },
{ 1, I2C2_BASE_ADDR, I2C_QUIRK_FLAG },
{ 2, I2C3_BASE_ADDR, I2C_QUIRK_FLAG },
{ 3, I2C4_BASE_ADDR, I2C_QUIRK_FLAG },
#else
{ 0, I2C1_BASE_ADDR, 0 },
{ 1, I2C2_BASE_ADDR, 0 },
{ 2, I2C3_BASE_ADDR, 0 },
{ 3, I2C4_BASE_ADDR, 0 },
#endif
};
struct mxc_i2c_bus *i2c_get_base(struct i2c_adapter *adap)
{
return &mxc_i2c_buses[adap->hwadapnr];
}
static int mxc_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer,
int len)
{
return bus_i2c_read(i2c_get_base(adap), chip, addr, alen, buffer, len);
}
static int mxc_i2c_write(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer,
int len)
{
return bus_i2c_write(i2c_get_base(adap), chip, addr, alen, buffer, len);
}
/*
* Test if a chip at a given address responds (probe the chip)
*/
static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
{
return bus_i2c_write(i2c_get_base(adap), chip, 0, 0, NULL, 0);
}
int __enable_i2c_clk(unsigned char enable, unsigned i2c_num)
{
return 1;
}
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
__attribute__((weak, alias("__enable_i2c_clk")));
void bus_i2c_init(int index, int speed, int unused,
int (*idle_bus_fn)(void *p), void *idle_bus_data)
{
int ret;
if (index >= ARRAY_SIZE(mxc_i2c_buses)) {
debug("Error i2c index\n");
return;
}
/*
* Warning: Be careful to allow the assignment to a static
* variable here. This function could be called while U-Boot is
* still running in flash memory. So such assignment is equal
* to write data to flash without erasing.
*/
if (idle_bus_fn)
mxc_i2c_buses[index].idle_bus_fn = idle_bus_fn;
if (idle_bus_data)
mxc_i2c_buses[index].idle_bus_data = idle_bus_data;
ret = enable_i2c_clk(1, index);
if (ret < 0) {
debug("I2C-%d clk fail to enable.\n", index);
return;
}
bus_i2c_set_bus_speed(&mxc_i2c_buses[index], speed);
}
/*
* Early init I2C for prepare read the clk through I2C.
*/
void i2c_early_init_f(void)
{
ulong base = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].base;
bool quirk = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].driver_data
& I2C_QUIRK_FLAG ? true : false;
int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
/* Set I2C divider value */
writeb(I2C_IFDR_DIV_CONSERVATIVE, base + (IFDR << reg_shift));
/* Reset module */
writeb(I2CR_IDIS, base + (I2CR << reg_shift));
writeb(0, base + (I2SR << reg_shift));
/* Enable I2C */
writeb(I2CR_IEN, base + (I2CR << reg_shift));
}
/*
* Init I2C Bus
*/
static void mxc_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
bus_i2c_init(adap->hwadapnr, speed, slaveaddr, NULL, NULL);
}
/*
* Set I2C Speed
*/
static u32 mxc_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
return bus_i2c_set_bus_speed(i2c_get_base(adap), speed);
}
/*
* Register mxc i2c adapters
*/
#ifdef CONFIG_SYS_I2C_MXC_I2C1
U_BOOT_I2C_ADAP_COMPLETE(mxc0, mxc_i2c_init, mxc_i2c_probe,
mxc_i2c_read, mxc_i2c_write,
mxc_i2c_set_bus_speed,
CONFIG_SYS_MXC_I2C1_SPEED,
CONFIG_SYS_MXC_I2C1_SLAVE, 0)
#endif
#ifdef CONFIG_SYS_I2C_MXC_I2C2
U_BOOT_I2C_ADAP_COMPLETE(mxc1, mxc_i2c_init, mxc_i2c_probe,
mxc_i2c_read, mxc_i2c_write,
mxc_i2c_set_bus_speed,
CONFIG_SYS_MXC_I2C2_SPEED,
CONFIG_SYS_MXC_I2C2_SLAVE, 1)
#endif
#ifdef CONFIG_SYS_I2C_MXC_I2C3
U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe,
mxc_i2c_read, mxc_i2c_write,
mxc_i2c_set_bus_speed,
CONFIG_SYS_MXC_I2C3_SPEED,
CONFIG_SYS_MXC_I2C3_SLAVE, 2)
#endif
#ifdef CONFIG_SYS_I2C_MXC_I2C4
U_BOOT_I2C_ADAP_COMPLETE(mxc3, mxc_i2c_init, mxc_i2c_probe,
mxc_i2c_read, mxc_i2c_write,
mxc_i2c_set_bus_speed,
CONFIG_SYS_MXC_I2C4_SPEED,
CONFIG_SYS_MXC_I2C4_SLAVE, 3)
#endif
#else
static int mxc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
return bus_i2c_set_bus_speed(i2c_bus, speed);
}
static int mxc_i2c_probe(struct udevice *bus)
{
struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
const void *fdt = gd->fdt_blob;
int node = bus->of_offset;
fdt_addr_t addr;
int ret, ret2;
i2c_bus->driver_data = dev_get_driver_data(bus);
addr = dev_get_addr(bus);
if (addr == FDT_ADDR_T_NONE)
return -ENODEV;
i2c_bus->base = addr;
i2c_bus->index = bus->seq;
i2c_bus->bus = bus;
/* Enable clk */
ret = enable_i2c_clk(1, bus->seq);
if (ret < 0)
return ret;
/*
* See Documentation/devicetree/bindings/i2c/i2c-imx.txt
* Use gpio to force bus idle when necessary.
*/
ret = fdt_find_string(fdt, node, "pinctrl-names", "gpio");
if (ret < 0) {
dev_info(dev, "i2c bus %d at %lu, no gpio pinctrl state.\n", bus->seq, i2c_bus->base);
} else {
ret = gpio_request_by_name_nodev(fdt, node, "scl-gpios",
0, &i2c_bus->scl_gpio,
GPIOD_IS_OUT);
ret2 = gpio_request_by_name_nodev(fdt, node, "sda-gpios",
0, &i2c_bus->sda_gpio,
GPIOD_IS_OUT);
if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) |
!dm_gpio_is_valid(&i2c_bus->scl_gpio) |
ret | ret2) {
dev_err(dev, "i2c bus %d at %lu, fail to request scl/sda gpio\n", bus->seq, i2c_bus->base);
return -ENODEV;
}
}
ret = i2c_idle_bus(i2c_bus);
if (ret < 0) {
/* Disable clk */
enable_i2c_clk(0, bus->seq);
return ret;
}
/*
* Pinmux settings are in board file now, until pinmux is supported,
* we can set pinmux here in probe function.
*/
debug("i2c : controller bus %d at %lu , speed %d: ",
bus->seq, i2c_bus->base,
i2c_bus->speed);
return 0;
}
static int mxc_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
u32 chip_flags)
{
int ret;
struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
ret = i2c_init_transfer(i2c_bus, chip_addr, 0, 0);
if (ret < 0) {
debug("%s failed, ret = %d\n", __func__, ret);
return ret;
}
i2c_imx_stop(i2c_bus);
return 0;
}
static int mxc_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
{
struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus);
int ret = 0;
ulong base = i2c_bus->base;
int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ?
VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT;
/*
* Here the 3rd parameter addr and the 4th one alen are set to 0,
* because here we only want to send out chip address. The register
* address is wrapped in msg.
*/
ret = i2c_init_transfer(i2c_bus, msg->addr, 0, 0);
if (ret < 0) {
debug("i2c_init_transfer error: %d\n", ret);
return ret;
}
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD)
ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
else {
ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len);
if (ret)
break;
if (next_is_read) {
/* Reuse ret */
ret = readb(base + (I2CR << reg_shift));
ret |= I2CR_RSTA;
writeb(ret, base + (I2CR << reg_shift));
ret = tx_byte(i2c_bus, (msg->addr << 1) | 1);
if (ret < 0) {
i2c_imx_stop(i2c_bus);
break;
}
}
}
}
if (ret)
debug("i2c_write: error sending\n");
i2c_imx_stop(i2c_bus);
return ret;
}
static const struct dm_i2c_ops mxc_i2c_ops = {
.xfer = mxc_i2c_xfer,
.probe_chip = mxc_i2c_probe_chip,
.set_bus_speed = mxc_i2c_set_bus_speed,
};
static const struct udevice_id mxc_i2c_ids[] = {
{ .compatible = "fsl,imx21-i2c", },
{ .compatible = "fsl,vf610-i2c", .data = I2C_QUIRK_FLAG, },
{}
};
U_BOOT_DRIVER(i2c_mxc) = {
.name = "i2c_mxc",
.id = UCLASS_I2C,
.of_match = mxc_i2c_ids,
.probe = mxc_i2c_probe,
.priv_auto_alloc_size = sizeof(struct mxc_i2c_bus),
.ops = &mxc_i2c_ops,
};
#endif

View File

@@ -0,0 +1,320 @@
/*
* Freescale i.MX28 I2C Driver
*
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
* on behalf of DENX Software Engineering GmbH
*
* Partly based on Linux kernel i2c-mxs.c driver:
* Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
*
* Which was based on a (non-working) driver which was:
* Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <malloc.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#define MXS_I2C_MAX_TIMEOUT 1000000
static struct mxs_i2c_regs *mxs_i2c_get_base(struct i2c_adapter *adap)
{
if (adap->hwadapnr == 0)
return (struct mxs_i2c_regs *)MXS_I2C0_BASE;
else
return (struct mxs_i2c_regs *)MXS_I2C1_BASE;
}
static unsigned int mxs_i2c_get_bus_speed(struct i2c_adapter *adap)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
uint32_t timing0;
timing0 = readl(&i2c_regs->hw_i2c_timing0);
/*
* This is a reverse version of the algorithm presented in
* i2c_set_bus_speed(). Please refer there for details.
*/
return clk / ((((timing0 >> 16) - 3) * 2) + 38);
}
static uint mxs_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
/*
* The timing derivation algorithm. There is no documentation for this
* algorithm available, it was derived by using the scope and fiddling
* with constants until the result observed on the scope was good enough
* for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be
* possible to assume the algorithm works for other frequencies as well.
*
* Note it was necessary to cap the frequency on both ends as it's not
* possible to configure completely arbitrary frequency for the I2C bus
* clock.
*/
uint32_t clk = mxc_get_clock(MXC_XTAL_CLK);
uint32_t base = ((clk / speed) - 38) / 2;
uint16_t high_count = base + 3;
uint16_t low_count = base - 3;
uint16_t rcv_count = (high_count * 3) / 4;
uint16_t xmit_count = low_count / 4;
if (speed > 540000) {
printf("MXS I2C: Speed too high (%d Hz)\n", speed);
return -EINVAL;
}
if (speed < 12000) {
printf("MXS I2C: Speed too low (%d Hz)\n", speed);
return -EINVAL;
}
writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0);
writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1);
writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) |
(0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET),
&i2c_regs->hw_i2c_timing2);
return 0;
}
static void mxs_i2c_reset(struct i2c_adapter *adap)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
int ret;
int speed = mxs_i2c_get_bus_speed(adap);
ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg);
if (ret) {
debug("MXS I2C: Block reset timeout\n");
return;
}
writel(I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | I2C_CTRL1_NO_SLAVE_ACK_IRQ |
I2C_CTRL1_EARLY_TERM_IRQ | I2C_CTRL1_MASTER_LOSS_IRQ |
I2C_CTRL1_SLAVE_STOP_IRQ | I2C_CTRL1_SLAVE_IRQ,
&i2c_regs->hw_i2c_ctrl1_clr);
writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set);
mxs_i2c_set_bus_speed(adap, speed);
}
static void mxs_i2c_setup_read(struct i2c_adapter *adap, uint8_t chip, int len)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
writel(I2C_QUEUECMD_RETAIN_CLOCK | I2C_QUEUECMD_PRE_SEND_START |
I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION |
(1 << I2C_QUEUECMD_XFER_COUNT_OFFSET),
&i2c_regs->hw_i2c_queuecmd);
writel((chip << 1) | 1, &i2c_regs->hw_i2c_data);
writel(I2C_QUEUECMD_SEND_NAK_ON_LAST | I2C_QUEUECMD_MASTER_MODE |
(len << I2C_QUEUECMD_XFER_COUNT_OFFSET) |
I2C_QUEUECMD_POST_SEND_STOP, &i2c_regs->hw_i2c_queuecmd);
writel(I2C_QUEUECTRL_QUEUE_RUN, &i2c_regs->hw_i2c_queuectrl_set);
}
static int mxs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buf, int blen, int stop)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
uint32_t data, tmp;
int i, remain, off;
int timeout = MXS_I2C_MAX_TIMEOUT;
if ((alen > 4) || (alen == 0)) {
debug("MXS I2C: Invalid address length\n");
return -EINVAL;
}
if (stop)
stop = I2C_QUEUECMD_POST_SEND_STOP;
writel(I2C_QUEUECMD_PRE_SEND_START |
I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION |
((blen + alen + 1) << I2C_QUEUECMD_XFER_COUNT_OFFSET) | stop,
&i2c_regs->hw_i2c_queuecmd);
data = (chip << 1) << 24;
for (i = 0; i < alen; i++) {
data >>= 8;
data |= ((char *)&addr)[alen - i - 1] << 24;
if ((i & 3) == 2)
writel(data, &i2c_regs->hw_i2c_data);
}
off = i;
for (; i < off + blen; i++) {
data >>= 8;
data |= buf[i - off] << 24;
if ((i & 3) == 2)
writel(data, &i2c_regs->hw_i2c_data);
}
remain = 24 - ((i & 3) * 8);
if (remain)
writel(data >> remain, &i2c_regs->hw_i2c_data);
writel(I2C_QUEUECTRL_QUEUE_RUN, &i2c_regs->hw_i2c_queuectrl_set);
while (--timeout) {
tmp = readl(&i2c_regs->hw_i2c_queuestat);
if (tmp & I2C_QUEUESTAT_WR_QUEUE_EMPTY)
break;
}
if (!timeout) {
debug("MXS I2C: Failed transmitting data!\n");
return -EINVAL;
}
return 0;
}
static int mxs_i2c_wait_for_ack(struct i2c_adapter *adap)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
uint32_t tmp;
int timeout = MXS_I2C_MAX_TIMEOUT;
for (;;) {
tmp = readl(&i2c_regs->hw_i2c_ctrl1);
if (tmp & I2C_CTRL1_NO_SLAVE_ACK_IRQ) {
debug("MXS I2C: No slave ACK\n");
goto err;
}
if (tmp & (
I2C_CTRL1_EARLY_TERM_IRQ | I2C_CTRL1_MASTER_LOSS_IRQ |
I2C_CTRL1_SLAVE_STOP_IRQ | I2C_CTRL1_SLAVE_IRQ)) {
debug("MXS I2C: Error (CTRL1 = %08x)\n", tmp);
goto err;
}
if (tmp & I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ)
break;
if (!timeout--) {
debug("MXS I2C: Operation timed out\n");
goto err;
}
udelay(1);
}
return 0;
err:
mxs_i2c_reset(adap);
return 1;
}
static int mxs_i2c_if_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer,
int len)
{
struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap);
uint32_t tmp = 0;
int timeout = MXS_I2C_MAX_TIMEOUT;
int ret;
int i;
ret = mxs_i2c_write(adap, chip, addr, alen, NULL, 0, 0);
if (ret) {
debug("MXS I2C: Failed writing address\n");
return ret;
}
ret = mxs_i2c_wait_for_ack(adap);
if (ret) {
debug("MXS I2C: Failed writing address\n");
return ret;
}
mxs_i2c_setup_read(adap, chip, len);
ret = mxs_i2c_wait_for_ack(adap);
if (ret) {
debug("MXS I2C: Failed reading address\n");
return ret;
}
for (i = 0; i < len; i++) {
if (!(i & 3)) {
while (--timeout) {
tmp = readl(&i2c_regs->hw_i2c_queuestat);
if (!(tmp & I2C_QUEUESTAT_RD_QUEUE_EMPTY))
break;
}
if (!timeout) {
debug("MXS I2C: Failed receiving data!\n");
return -ETIMEDOUT;
}
tmp = readl(&i2c_regs->hw_i2c_queuedata);
}
buffer[i] = tmp & 0xff;
tmp >>= 8;
}
return 0;
}
static int mxs_i2c_if_write(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, uint8_t *buffer,
int len)
{
int ret;
ret = mxs_i2c_write(adap, chip, addr, alen, buffer, len, 1);
if (ret) {
debug("MXS I2C: Failed writing address\n");
return ret;
}
ret = mxs_i2c_wait_for_ack(adap);
if (ret)
debug("MXS I2C: Failed writing address\n");
return ret;
}
static int mxs_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
{
int ret;
ret = mxs_i2c_write(adap, chip, 0, 1, NULL, 0, 1);
if (!ret)
ret = mxs_i2c_wait_for_ack(adap);
mxs_i2c_reset(adap);
return ret;
}
static void mxs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
mxs_i2c_reset(adap);
mxs_i2c_set_bus_speed(adap, speed);
return;
}
U_BOOT_I2C_ADAP_COMPLETE(mxs0, mxs_i2c_init, mxs_i2c_probe,
mxs_i2c_if_read, mxs_i2c_if_write,
mxs_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, 0, 0)
U_BOOT_I2C_ADAP_COMPLETE(mxs1, mxs_i2c_init, mxs_i2c_probe,
mxs_i2c_if_read, mxs_i2c_if_write,
mxs_i2c_set_bus_speed,
CONFIG_SYS_I2C_SPEED, 0, 1)

View File

@@ -0,0 +1,771 @@
/*
* Basic I2C functions
*
* Copyright (c) 2004 Texas Instruments
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: Jian Zhang jzhang@ti.com, Texas Instruments
*
* Copyright (c) 2003 Wolfgang Denk, wd@denx.de
* Rewritten to fit into the current U-Boot framework
*
* Adapted for OMAP2420 I2C, r-woodruff2@ti.com
*
* Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
* New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4
* (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older
* OMAPs and derivatives as well. The only anticipated exception would
* be the OMAP2420, which shall require driver modification.
* - Rewritten i2c_read to operate correctly with all types of chips
* (old function could not read consistent data from some I2C slaves).
* - Optimized i2c_write.
* - New i2c_probe, performs write access vs read. The old probe could
* hang the system under certain conditions (e.g. unconfigured pads).
* - The read/write/probe functions try to identify unconfigured bus.
* - Status functions now read irqstatus_raw as per TRM guidelines
* (except for OMAP243X and OMAP34XX).
* - Driver now supports up to I2C5 (OMAP5).
*
* Copyright (c) 2014 Hannes Schmelzer <oe5hpm@oevsv.at>, B&R
* - Added support for set_speed
*
*/
#include <common.h>
#include <i2c.h>
#include <asm/arch/i2c.h>
#include <asm/io.h>
#include "omap24xx_i2c.h"
DECLARE_GLOBAL_DATA_PTR;
#define I2C_TIMEOUT 1000
/* Absolutely safe for status update at 100 kHz I2C: */
#define I2C_WAIT 200
static int wait_for_bb(struct i2c_adapter *adap);
static struct i2c *omap24_get_base(struct i2c_adapter *adap);
static u16 wait_for_event(struct i2c_adapter *adap);
static void flush_fifo(struct i2c_adapter *adap);
static int omap24_i2c_findpsc(u32 *pscl, u32 *psch, uint speed)
{
unsigned int sampleclk, prescaler;
int fsscll, fssclh;
speed <<= 1;
prescaler = 0;
/*
* some divisors may cause a precission loss, but shouldn't
* be a big thing, because i2c_clk is then allready very slow.
*/
while (prescaler <= 0xFF) {
sampleclk = I2C_IP_CLK / (prescaler+1);
fsscll = sampleclk / speed;
fssclh = fsscll;
fsscll -= I2C_FASTSPEED_SCLL_TRIM;
fssclh -= I2C_FASTSPEED_SCLH_TRIM;
if (((fsscll > 0) && (fssclh > 0)) &&
((fsscll <= (255-I2C_FASTSPEED_SCLL_TRIM)) &&
(fssclh <= (255-I2C_FASTSPEED_SCLH_TRIM)))) {
if (pscl)
*pscl = fsscll;
if (psch)
*psch = fssclh;
return prescaler;
}
prescaler++;
}
return -1;
}
static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
{
struct i2c *i2c_base = omap24_get_base(adap);
int psc, fsscll = 0, fssclh = 0;
int hsscll = 0, hssclh = 0;
u32 scll = 0, sclh = 0;
if (speed >= OMAP_I2C_HIGH_SPEED) {
/* High speed */
psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
psc -= 1;
if (psc < I2C_PSC_MIN) {
printf("Error : I2C unsupported prescaler %d\n", psc);
return -1;
}
/* For first phase of HS mode */
fsscll = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
fssclh = fsscll;
fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
if (((fsscll < 0) || (fssclh < 0)) ||
((fsscll > 255) || (fssclh > 255))) {
puts("Error : I2C initializing first phase clock\n");
return -1;
}
/* For second phase of HS mode */
hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed);
hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
if (((fsscll < 0) || (fssclh < 0)) ||
((fsscll > 255) || (fssclh > 255))) {
puts("Error : I2C initializing second phase clock\n");
return -1;
}
scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll;
sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh;
} else {
/* Standard and fast speed */
psc = omap24_i2c_findpsc(&scll, &sclh, speed);
if (0 > psc) {
puts("Error : I2C initializing clock\n");
return -1;
}
}
adap->speed = speed;
adap->waitdelay = (10000000 / speed) * 2; /* wait for 20 clkperiods */
writew(0, &i2c_base->con);
writew(psc, &i2c_base->psc);
writew(scll, &i2c_base->scll);
writew(sclh, &i2c_base->sclh);
writew(I2C_CON_EN, &i2c_base->con);
writew(0xFFFF, &i2c_base->stat); /* clear all pending status */
return 0;
}
static void omap24_i2c_deblock(struct i2c_adapter *adap)
{
struct i2c *i2c_base = omap24_get_base(adap);
int i;
u16 systest;
u16 orgsystest;
/* set test mode ST_EN = 1 */
orgsystest = readw(&i2c_base->systest);
systest = orgsystest;
/* enable testmode */
systest |= I2C_SYSTEST_ST_EN;
writew(systest, &i2c_base->systest);
systest &= ~I2C_SYSTEST_TMODE_MASK;
systest |= 3 << I2C_SYSTEST_TMODE_SHIFT;
writew(systest, &i2c_base->systest);
/* set SCL, SDA = 1 */
systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
writew(systest, &i2c_base->systest);
udelay(10);
/* toggle scl 9 clocks */
for (i = 0; i < 9; i++) {
/* SCL = 0 */
systest &= ~I2C_SYSTEST_SCL_O;
writew(systest, &i2c_base->systest);
udelay(10);
/* SCL = 1 */
systest |= I2C_SYSTEST_SCL_O;
writew(systest, &i2c_base->systest);
udelay(10);
}
/* send stop */
systest &= ~I2C_SYSTEST_SDA_O;
writew(systest, &i2c_base->systest);
udelay(10);
systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
writew(systest, &i2c_base->systest);
udelay(10);
/* restore original mode */
writew(orgsystest, &i2c_base->systest);
}
static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct i2c *i2c_base = omap24_get_base(adap);
int timeout = I2C_TIMEOUT;
int deblock = 1;
retry:
if (readw(&i2c_base->con) & I2C_CON_EN) {
writew(0, &i2c_base->con);
udelay(50000);
}
writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
udelay(1000);
writew(I2C_CON_EN, &i2c_base->con);
while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
if (timeout <= 0) {
puts("ERROR: Timeout in soft-reset\n");
return;
}
udelay(1000);
}
if (0 != omap24_i2c_setspeed(adap, speed)) {
printf("ERROR: failed to setup I2C bus-speed!\n");
return;
}
/* own address */
writew(slaveadd, &i2c_base->oa);
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
/*
* Have to enable interrupts for OMAP2/3, these IPs don't have
* an 'irqstatus_raw' register and we shall have to poll 'stat'
*/
writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
#endif
udelay(1000);
flush_fifo(adap);
writew(0xFFFF, &i2c_base->stat);
/* Handle possible failed I2C state */
if (wait_for_bb(adap))
if (deblock == 1) {
omap24_i2c_deblock(adap);
deblock = 0;
goto retry;
}
}
static void flush_fifo(struct i2c_adapter *adap)
{
struct i2c *i2c_base = omap24_get_base(adap);
u16 stat;
/*
* note: if you try and read data when its not there or ready
* you get a bus error
*/
while (1) {
stat = readw(&i2c_base->stat);
if (stat == I2C_STAT_RRDY) {
readb(&i2c_base->data);
writew(I2C_STAT_RRDY, &i2c_base->stat);
udelay(1000);
} else
break;
}
}
/*
* i2c_probe: Use write access. Allows to identify addresses that are
* write-only (like the config register of dual-port EEPROMs)
*/
static int omap24_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
struct i2c *i2c_base = omap24_get_base(adap);
u16 status;
int res = 1; /* default = fail */
if (chip == readw(&i2c_base->oa))
return res;
/* Wait until bus is free */
if (wait_for_bb(adap))
return res;
/* No data transfer, slave addr only */
writew(chip, &i2c_base->sa);
/* Stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con);
status = wait_for_event(adap);
if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
/*
* With current high-level command implementation, notifying
* the user shall flood the console with 127 messages. If
* silent exit is desired upon unconfigured bus, remove the
* following 'if' section:
*/
if (status == I2C_STAT_XRDY)
printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n",
adap->hwadapnr, status);
goto pr_exit;
}
/* Check for ACK (!NAK) */
if (!(status & I2C_STAT_NACK)) {
res = 0; /* Device found */
udelay(adap->waitdelay);/* Required by AM335X in SPL */
/* Abort transfer (force idle state) */
writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
udelay(1000);
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con); /* STP */
}
pr_exit:
flush_fifo(adap);
writew(0xFFFF, &i2c_base->stat);
return res;
}
/*
* i2c_read: Function now uses a single I2C read transaction with bulk transfer
* of the requested number of bytes (note that the 'i2c md' command
* limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is
* defined in the board config header, this transaction shall be with
* Repeated Start (Sr) between the address and data phases; otherwise
* Stop-Start (P-S) shall be used (some I2C chips do require a P-S).
* The address (reg offset) may be 0, 1 or 2 bytes long.
* Function now reads correctly from chips that return more than one
* byte of data per addressed register (like TI temperature sensors),
* or that do not need a register address at all (such as some clock
* distributors).
*/
static int omap24_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
struct i2c *i2c_base = omap24_get_base(adap);
int i2c_error = 0;
u16 status;
if (alen < 0) {
puts("I2C read: addr len < 0\n");
return 1;
}
if (len < 0) {
puts("I2C read: data len < 0\n");
return 1;
}
if (buffer == NULL) {
puts("I2C read: NULL pointer passed\n");
return 1;
}
if (alen > 2) {
printf("I2C read: addr len %d not supported\n", alen);
return 1;
}
if (addr + len > (1 << 16)) {
puts("I2C read: address out of range\n");
return 1;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
/* Wait until bus not busy */
if (wait_for_bb(adap))
return 1;
/* Zero, one or two bytes reg address (offset) */
writew(alen, &i2c_base->cnt);
/* Set slave address */
writew(chip, &i2c_base->sa);
if (alen) {
/* Must write reg offset first */
#ifdef CONFIG_I2C_REPEATED_START
/* No stop bit, use Repeated Start (Sr) */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
I2C_CON_TRX, &i2c_base->con);
#else
/* Stop - Start (P-S) */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
I2C_CON_TRX, &i2c_base->con);
#endif
/* Send register offset */
while (1) {
status = wait_for_event(adap);
/* Try to identify bus that is not padconf'd for I2C */
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
adap->hwadapnr, status);
goto rd_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
i2c_error = 1;
printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
status);
goto rd_exit;
}
if (alen) {
if (status & I2C_STAT_XRDY) {
alen--;
/* Do we have to use byte access? */
writeb((addr >> (8 * alen)) & 0xff,
&i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
}
}
if (status & I2C_STAT_ARDY) {
writew(I2C_STAT_ARDY, &i2c_base->stat);
break;
}
}
}
/* Set slave address */
writew(chip, &i2c_base->sa);
/* Read len bytes from slave */
writew(len, &i2c_base->cnt);
/* Need stop bit here */
writew(I2C_CON_EN | I2C_CON_MST |
I2C_CON_STT | I2C_CON_STP,
&i2c_base->con);
/* Receive data */
while (1) {
status = wait_for_event(adap);
/*
* Try to identify bus that is not padconf'd for I2C. This
* state could be left over from previous transactions if
* the address phase is skipped due to alen=0.
*/
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
adap->hwadapnr, status);
goto rd_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
i2c_error = 1;
goto rd_exit;
}
if (status & I2C_STAT_RRDY) {
*buffer++ = readb(&i2c_base->data);
writew(I2C_STAT_RRDY, &i2c_base->stat);
}
if (status & I2C_STAT_ARDY) {
writew(I2C_STAT_ARDY, &i2c_base->stat);
break;
}
}
rd_exit:
flush_fifo(adap);
writew(0xFFFF, &i2c_base->stat);
return i2c_error;
}
/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
static int omap24_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
struct i2c *i2c_base = omap24_get_base(adap);
int i;
u16 status;
int i2c_error = 0;
int timeout = I2C_TIMEOUT;
if (alen < 0) {
puts("I2C write: addr len < 0\n");
return 1;
}
if (len < 0) {
puts("I2C write: data len < 0\n");
return 1;
}
if (buffer == NULL) {
puts("I2C write: NULL pointer passed\n");
return 1;
}
if (alen > 2) {
printf("I2C write: addr len %d not supported\n", alen);
return 1;
}
if (addr + len > (1 << 16)) {
printf("I2C write: address 0x%x + 0x%x out of range\n",
addr, len);
return 1;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
/* Wait until bus not busy */
if (wait_for_bb(adap))
return 1;
/* Start address phase - will write regoffset + len bytes data */
writew(alen + len, &i2c_base->cnt);
/* Set slave address */
writew(chip, &i2c_base->sa);
/* Stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
I2C_CON_STP, &i2c_base->con);
while (alen) {
/* Must write reg offset (one or two bytes) */
status = wait_for_event(adap);
/* Try to identify bus that is not padconf'd for I2C */
if (status == I2C_STAT_XRDY) {
i2c_error = 2;
printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
adap->hwadapnr, status);
goto wr_exit;
}
if (status == 0 || (status & I2C_STAT_NACK)) {
i2c_error = 1;
printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
status);
goto wr_exit;
}
if (status & I2C_STAT_XRDY) {
alen--;
writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
status);
goto wr_exit;
}
}
/* Address phase is over, now write data */
for (i = 0; i < len; i++) {
status = wait_for_event(adap);
if (status == 0 || (status & I2C_STAT_NACK)) {
i2c_error = 1;
printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
status);
goto wr_exit;
}
if (status & I2C_STAT_XRDY) {
writeb(buffer[i], &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
printf("i2c_write: bus not ready for data Tx (i=%d)\n",
i);
goto wr_exit;
}
}
/*
* poll ARDY bit for making sure that last byte really has been
* transferred on the bus.
*/
do {
status = wait_for_event(adap);
} while (!(status & I2C_STAT_ARDY) && timeout--);
if (timeout <= 0)
printf("i2c_write: timed out writig last byte!\n");
wr_exit:
flush_fifo(adap);
writew(0xFFFF, &i2c_base->stat);
return i2c_error;
}
/*
* Wait for the bus to be free by checking the Bus Busy (BB)
* bit to become clear
*/
static int wait_for_bb(struct i2c_adapter *adap)
{
struct i2c *i2c_base = omap24_get_base(adap);
int timeout = I2C_TIMEOUT;
u16 stat;
writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
#else
/* Read RAW status */
while ((stat = readw(&i2c_base->irqstatus_raw) &
I2C_STAT_BB) && timeout--) {
#endif
writew(stat, &i2c_base->stat);
udelay(adap->waitdelay);
}
if (timeout <= 0) {
printf("Timed out in wait_for_bb: status=%04x\n",
stat);
return 1;
}
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
return 0;
}
/*
* Wait for the I2C controller to complete current action
* and update status
*/
static u16 wait_for_event(struct i2c_adapter *adap)
{
struct i2c *i2c_base = omap24_get_base(adap);
u16 status;
int timeout = I2C_TIMEOUT;
do {
udelay(adap->waitdelay);
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
status = readw(&i2c_base->stat);
#else
/* Read RAW status */
status = readw(&i2c_base->irqstatus_raw);
#endif
} while (!(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
I2C_STAT_AL)) && timeout--);
if (timeout <= 0) {
printf("Timed out in wait_for_event: status=%04x\n",
status);
/*
* If status is still 0 here, probably the bus pads have
* not been configured for I2C, and/or pull-ups are missing.
*/
printf("Check if pads/pull-ups of bus %d are properly configured\n",
adap->hwadapnr);
writew(0xFFFF, &i2c_base->stat);
status = 0;
}
return status;
}
static struct i2c *omap24_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
case 0:
return (struct i2c *)I2C_BASE1;
break;
case 1:
return (struct i2c *)I2C_BASE2;
break;
#if (I2C_BUS_MAX > 2)
case 2:
return (struct i2c *)I2C_BASE3;
break;
#if (I2C_BUS_MAX > 3)
case 3:
return (struct i2c *)I2C_BASE4;
break;
#if (I2C_BUS_MAX > 4)
case 4:
return (struct i2c *)I2C_BASE5;
break;
#endif
#endif
#endif
default:
printf("wrong hwadapnr: %d\n", adap->hwadapnr);
break;
}
return NULL;
}
#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED1)
#define CONFIG_SYS_OMAP24_I2C_SPEED1 CONFIG_SYS_OMAP24_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE1)
#define CONFIG_SYS_OMAP24_I2C_SLAVE1 CONFIG_SYS_OMAP24_I2C_SLAVE
#endif
U_BOOT_I2C_ADAP_COMPLETE(omap24_0, omap24_i2c_init, omap24_i2c_probe,
omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
CONFIG_SYS_OMAP24_I2C_SPEED,
CONFIG_SYS_OMAP24_I2C_SLAVE,
0)
U_BOOT_I2C_ADAP_COMPLETE(omap24_1, omap24_i2c_init, omap24_i2c_probe,
omap24_i2c_read, omap24_i2c_write, omap24_i2c_setspeed,
CONFIG_SYS_OMAP24_I2C_SPEED1,
CONFIG_SYS_OMAP24_I2C_SLAVE1,
1)
#if (I2C_BUS_MAX > 2)
#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED2)
#define CONFIG_SYS_OMAP24_I2C_SPEED2 CONFIG_SYS_OMAP24_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE2)
#define CONFIG_SYS_OMAP24_I2C_SLAVE2 CONFIG_SYS_OMAP24_I2C_SLAVE
#endif
U_BOOT_I2C_ADAP_COMPLETE(omap24_2, omap24_i2c_init, omap24_i2c_probe,
omap24_i2c_read, omap24_i2c_write, NULL,
CONFIG_SYS_OMAP24_I2C_SPEED2,
CONFIG_SYS_OMAP24_I2C_SLAVE2,
2)
#if (I2C_BUS_MAX > 3)
#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED3)
#define CONFIG_SYS_OMAP24_I2C_SPEED3 CONFIG_SYS_OMAP24_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE3)
#define CONFIG_SYS_OMAP24_I2C_SLAVE3 CONFIG_SYS_OMAP24_I2C_SLAVE
#endif
U_BOOT_I2C_ADAP_COMPLETE(omap24_3, omap24_i2c_init, omap24_i2c_probe,
omap24_i2c_read, omap24_i2c_write, NULL,
CONFIG_SYS_OMAP24_I2C_SPEED3,
CONFIG_SYS_OMAP24_I2C_SLAVE3,
3)
#if (I2C_BUS_MAX > 4)
#if !defined(CONFIG_SYS_OMAP24_I2C_SPEED4)
#define CONFIG_SYS_OMAP24_I2C_SPEED4 CONFIG_SYS_OMAP24_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_OMAP24_I2C_SLAVE4)
#define CONFIG_SYS_OMAP24_I2C_SLAVE4 CONFIG_SYS_OMAP24_I2C_SLAVE
#endif
U_BOOT_I2C_ADAP_COMPLETE(omap24_4, omap24_i2c_init, omap24_i2c_probe,
omap24_i2c_read, omap24_i2c_write, NULL,
CONFIG_SYS_OMAP24_I2C_SPEED4,
CONFIG_SYS_OMAP24_I2C_SLAVE4,
4)
#endif
#endif
#endif

View File

@@ -0,0 +1,154 @@
/*
* (C) Copyright 2004-2010
* Texas Instruments, <www.ti.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _OMAP2PLUS_I2C_H_
#define _OMAP2PLUS_I2C_H_
/* I2C masks */
/* I2C Interrupt Enable Register (I2C_IE): */
#define I2C_IE_GC_IE (1 << 5)
#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */
#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */
#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */
#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Status Register (I2C_STAT): */
#define I2C_STAT_SBD (1 << 15) /* Single byte data */
#define I2C_STAT_BB (1 << 12) /* Bus busy */
#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define I2C_STAT_AAS (1 << 9) /* Address as slave */
#define I2C_STAT_GC (1 << 5)
#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define I2C_STAT_ARDY (1 << 2) /* Register access ready */
#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */
#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */
/* I2C Interrupt Code Register (I2C_INTCODE): */
#define I2C_INTCODE_MASK 7
#define I2C_INTCODE_NONE 0
#define I2C_INTCODE_AL 1 /* Arbitration lost */
#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */
#define I2C_INTCODE_ARDY 3 /* Register access ready */
#define I2C_INTCODE_RRDY 4 /* Rcv data ready */
#define I2C_INTCODE_XRDY 5 /* Xmit data ready */
/* I2C Buffer Configuration Register (I2C_BUF): */
#define I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */
#define I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */
/* I2C Configuration Register (I2C_CON): */
#define I2C_CON_EN (1 << 15) /* I2C module enable */
#define I2C_CON_BE (1 << 14) /* Big endian mode */
#define I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */
#define I2C_CON_MST (1 << 10) /* Master/slave mode */
#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode */
/* (master mode only) */
#define I2C_CON_XA (1 << 8) /* Expand address */
#define I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */
#define I2C_CON_STT (1 << 0) /* Start condition (master mode only) */
/* I2C System Test Register (I2C_SYSTEST): */
#define I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define I2C_SYSTEST_FREE (1 << 14) /* Free running mode, on brkpoint) */
#define I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
#define I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
#define I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense input value */
#define I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive output value */
#define I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense input value */
#define I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive output value */
/* I2C System Status Register (I2C_SYSS): */
#define I2C_SYSS_RDONE (1 << 0) /* Internel reset monitoring */
#define I2C_SCLL_SCLL 0
#define I2C_SCLL_SCLL_M 0xFF
#define I2C_SCLL_HSSCLL 8
#define I2C_SCLH_HSSCLL_M 0xFF
#define I2C_SCLH_SCLH 0
#define I2C_SCLH_SCLH_M 0xFF
#define I2C_SCLH_HSSCLH 8
#define I2C_SCLH_HSSCLH_M 0xFF
#define OMAP_I2C_STANDARD 100000
#define OMAP_I2C_FAST_MODE 400000
#define OMAP_I2C_HIGH_SPEED 3400000
#define SYSTEM_CLOCK_12 12000000
#define SYSTEM_CLOCK_13 13000000
#define SYSTEM_CLOCK_192 19200000
#define SYSTEM_CLOCK_96 96000000
/* Use the reference value of 96MHz if not explicitly set by the board */
#ifndef I2C_IP_CLK
#define I2C_IP_CLK SYSTEM_CLOCK_96
#endif
/*
* The reference minimum clock for high speed is 19.2MHz.
* The linux 2.6.30 kernel uses this value.
* The reference minimum clock for fast mode is 9.6MHz
* The reference minimum clock for standard mode is 4MHz
* In TRM, the value of 12MHz is used.
*/
#ifndef I2C_INTERNAL_SAMPLING_CLK
#define I2C_INTERNAL_SAMPLING_CLK 19200000
#endif
/*
* The equation for the low and high time is
* tlow = scll + scll_trim = (sampling clock * tlow_duty) / speed
* thigh = sclh + sclh_trim = (sampling clock * (1 - tlow_duty)) / speed
*
* If the duty cycle is 50%
*
* tlow = scll + scll_trim = sampling clock / (2 * speed)
* thigh = sclh + sclh_trim = sampling clock / (2 * speed)
*
* In TRM
* scll_trim = 7
* sclh_trim = 5
*
* The linux 2.6.30 kernel uses
* scll_trim = 6
* sclh_trim = 6
*
* These are the trim values for standard and fast speed
*/
#ifndef I2C_FASTSPEED_SCLL_TRIM
#define I2C_FASTSPEED_SCLL_TRIM 6
#endif
#ifndef I2C_FASTSPEED_SCLH_TRIM
#define I2C_FASTSPEED_SCLH_TRIM 6
#endif
/* These are the trim values for high speed */
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM I2C_FASTSPEED_SCLL_TRIM
#endif
#ifndef I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM
#define I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM I2C_FASTSPEED_SCLH_TRIM
#endif
#define I2C_PSC_MAX 0x0f
#define I2C_PSC_MIN 0x00
#endif /* _OMAP24XX_I2C_H_ */

View File

@@ -0,0 +1,176 @@
/*
* File: drivers/i2c/pca9564.c
* Based on: drivers/i2c/s3c44b0_i2c.c
* Author:
*
* Created: 2009-06-23
* Description: PCA9564 i2c bridge driver
*
* Modified:
* Copyright 2009 CJSC "NII STT", http://www.niistt.ru/
*
* Bugs:
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <pca9564.h>
#include <asm/io.h>
#define PCA_STA (CONFIG_PCA9564_BASE + 0)
#define PCA_TO (CONFIG_PCA9564_BASE + 0)
#define PCA_DAT (CONFIG_PCA9564_BASE + (1 << 2))
#define PCA_ADR (CONFIG_PCA9564_BASE + (2 << 2))
#define PCA_CON (CONFIG_PCA9564_BASE + (3 << 2))
static unsigned char pca_read_reg(unsigned int reg)
{
return readb((void *)reg);
}
static void pca_write_reg(unsigned int reg, unsigned char value)
{
writeb(value, (void *)reg);
}
static int pca_wait_busy(void)
{
unsigned int timeout = 10000;
while (!(pca_read_reg(PCA_CON) & PCA_CON_SI) && --timeout)
udelay(1);
if (timeout == 0)
debug("I2C timeout!\n");
debug("CON = 0x%02x, STA = 0x%02x\n", pca_read_reg(PCA_CON),
pca_read_reg(PCA_STA));
return timeout ? 0 : 1;
}
/*=====================================================================*/
/* Public Functions */
/*=====================================================================*/
/*-----------------------------------------------------------------------
* Initialization
*/
void i2c_init(int speed, int slaveaddr)
{
pca_write_reg(PCA_CON, PCA_CON_ENSIO | speed);
}
/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.
*/
int i2c_probe(uchar chip)
{
unsigned char res;
pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_STA | PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1) | 1);
res = pca_wait_busy();
if ((res == 0) && (pca_read_reg(PCA_STA) == 0x48))
res = 1;
pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
return res;
}
/*
* Read/Write interface:
* chip: I2C chip address, range 0..127
* addr: Memory (register) address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Where to read/write the data
* len: How many bytes to read/write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1));
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
if (alen > 0) {
pca_write_reg(PCA_DAT, addr);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
udelay(500);
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, (chip << 1) | 1);
pca_wait_busy();
for (i = 0; i < len; ++i) {
if (i == len - 1)
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
else
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_AA);
pca_wait_busy();
buffer[i] = pca_read_reg(PCA_DAT);
}
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STO);
return 0;
}
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
pca_write_reg(PCA_CON, PCA_CON_ENSIO | PCA_CON_STA);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
pca_write_reg(PCA_DAT, chip << 1);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
if (alen > 0) {
pca_write_reg(PCA_DAT, addr);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
for (i = 0; i < len; ++i) {
pca_write_reg(PCA_DAT, buffer[i]);
pca_wait_busy();
pca_write_reg(PCA_CON, PCA_CON_ENSIO);
}
pca_write_reg(PCA_CON, PCA_CON_STO | PCA_CON_ENSIO);
return 0;
}

View File

@@ -0,0 +1,441 @@
/*
* (C) Copyright 2007-2009
* Stefan Roese, DENX Software Engineering, sr@denx.de.
*
* based on work by Anne Sophie Harnois <anne-sophie.harnois@nextream.fr>
*
* (C) Copyright 2001
* Bill Hunter, Wave 7 Optics, williamhunter@mediaone.net
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/ppc4xx.h>
#include <asm/ppc4xx-i2c.h>
#include <i2c.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
static inline struct ppc4xx_i2c *ppc4xx_get_i2c(int hwadapnr)
{
unsigned long base;
#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
defined(CONFIG_460EX) || defined(CONFIG_460GT)
base = CONFIG_SYS_PERIPHERAL_BASE + 0x00000700 + (hwadapnr * 0x100);
#elif defined(CONFIG_440) || defined(CONFIG_405EX)
/* all remaining 440 variants */
base = CONFIG_SYS_PERIPHERAL_BASE + 0x00000400 + (hwadapnr * 0x100);
#else
/* all 405 variants */
base = 0xEF600500 + (hwadapnr * 0x100);
#endif
return (struct ppc4xx_i2c *)base;
}
static void _i2c_bus_reset(struct i2c_adapter *adap)
{
struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
int i;
u8 dc;
/* Reset status register */
/* write 1 in SCMP and IRQA to clear these fields */
out_8(&i2c->sts, 0x0A);
/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
out_8(&i2c->extsts, 0x8F);
/* Place chip in the reset state */
out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST);
/* Check if bus is free */
dc = in_8(&i2c->directcntl);
if (!DIRCTNL_FREE(dc)){
/* Try to set bus free state */
out_8(&i2c->directcntl, IIC_DIRCNTL_SDAC | IIC_DIRCNTL_SCC);
/* Wait until we regain bus control */
for (i = 0; i < 100; ++i) {
dc = in_8(&i2c->directcntl);
if (DIRCTNL_FREE(dc))
break;
/* Toggle SCL line */
dc ^= IIC_DIRCNTL_SCC;
out_8(&i2c->directcntl, dc);
udelay(10);
dc ^= IIC_DIRCNTL_SCC;
out_8(&i2c->directcntl, dc);
}
}
/* Remove reset */
out_8(&i2c->xtcntlss, 0);
}
static void ppc4xx_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
int val, divisor;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
* Call board specific i2c bus reset routine before accessing the
* environment, which might be in a chip on that bus. For details
* about this problem see doc/I2C_Edge_Conditions.
*/
i2c_init_board();
#endif
/* Handle possible failed I2C state */
/* FIXME: put this into i2c_init_board()? */
_i2c_bus_reset(adap);
/* clear lo master address */
out_8(&i2c->lmadr, 0);
/* clear hi master address */
out_8(&i2c->hmadr, 0);
/* clear lo slave address */
out_8(&i2c->lsadr, 0);
/* clear hi slave address */
out_8(&i2c->hsadr, 0);
/* Clock divide Register */
/* set divisor according to freq_opb */
divisor = (get_OPB_freq() - 1) / 10000000;
if (divisor == 0)
divisor = 1;
out_8(&i2c->clkdiv, divisor);
/* no interrupts */
out_8(&i2c->intrmsk, 0);
/* clear transfer count */
out_8(&i2c->xfrcnt, 0);
/* clear extended control & stat */
/* write 1 in SRC SRS SWC SWS to clear these fields */
out_8(&i2c->xtcntlss, 0xF0);
/* Mode Control Register
Flush Slave/Master data buffer */
out_8(&i2c->mdcntl, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
val = in_8(&i2c->mdcntl);
/* Ignore General Call, slave transfers are ignored,
* disable interrupts, exit unknown bus state, enable hold
* SCL 100kHz normaly or FastMode for 400kHz and above
*/
val |= IIC_MDCNTL_EUBS | IIC_MDCNTL_HSCL;
if (speed >= 400000)
val |= IIC_MDCNTL_FSM;
out_8(&i2c->mdcntl, val);
/* clear control reg */
out_8(&i2c->cntl, 0x00);
}
/*
* This code tries to use the features of the 405GP i2c
* controller. It will transfer up to 4 bytes in one pass
* on the loop. It only does out_8((u8 *)lbz) to the buffer when it
* is possible to do out16(lhz) transfers.
*
* cmd_type is 0 for write 1 for read.
*
* addr_len can take any value from 0-255, it is only limited
* by the char, we could make it larger if needed. If it is
* 0 we skip the address write cycle.
*
* Typical case is a Write of an addr followd by a Read. The
* IBM FAQ does not cover this. On the last byte of the write
* we don't set the creg CHT bit but the RPST bit.
*
* It does not support address only transfers, there must be
* a data part. If you want to write the address yourself, put
* it in the data pointer.
*
* It does not support transfer to/from address 0.
*
* It does not check XFRCNT.
*/
static int _i2c_transfer(struct i2c_adapter *adap,
unsigned char cmd_type,
unsigned char chip,
unsigned char addr[],
unsigned char addr_len,
unsigned char data[],
unsigned short data_len)
{
struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
u8 *ptr;
int reading;
int tran, cnt;
int result;
int status;
int i;
u8 creg;
if (data == 0 || data_len == 0) {
/* Don't support data transfer of no length or to address 0 */
printf( "i2c_transfer: bad call\n" );
return IIC_NOK;
}
if (addr && addr_len) {
ptr = addr;
cnt = addr_len;
reading = 0;
} else {
ptr = data;
cnt = data_len;
reading = cmd_type;
}
/* Clear Stop Complete Bit */
out_8(&i2c->sts, IIC_STS_SCMP);
/* Check init */
i = 10;
do {
/* Get status */
status = in_8(&i2c->sts);
i--;
} while ((status & IIC_STS_PT) && (i > 0));
if (status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
return(result);
}
/* flush the Master/Slave Databuffers */
out_8(&i2c->mdcntl, in_8(&i2c->mdcntl) |
IIC_MDCNTL_FMDB | IIC_MDCNTL_FSDB);
/* need to wait 4 OPB clocks? code below should take that long */
/* 7-bit adressing */
out_8(&i2c->hmadr, 0);
out_8(&i2c->lmadr, chip);
tran = 0;
result = IIC_OK;
creg = 0;
while (tran != cnt && (result == IIC_OK)) {
int bc,j;
/*
* Control register =
* Normal transfer, 7-bits adressing, Transfer up to
* bc bytes, Normal start, Transfer is a sequence of transfers
*/
creg |= IIC_CNTL_PT;
bc = (cnt - tran) > 4 ? 4 : cnt - tran;
creg |= (bc - 1) << 4;
/* if the real cmd type is write continue trans */
if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt))
creg |= IIC_CNTL_CHT;
/* last part of address, prepare for repeated start on read */
if (cmd_type && (ptr == addr) && ((tran + bc) == cnt))
creg |= IIC_CNTL_RPST;
if (reading) {
creg |= IIC_CNTL_READ;
} else {
for(j = 0; j < bc; j++) {
/* Set buffer */
out_8(&i2c->mdbuf, ptr[tran + j]);
}
}
out_8(&i2c->cntl, creg);
/*
* Transfer is in progress
* we have to wait for upto 5 bytes of data
* 1 byte chip address+r/w bit then bc bytes
* of data.
* udelay(10) is 1 bit time at 100khz
* Doubled for slop. 20 is too small.
*/
i = 2 * 5 * 8;
do {
/* Get status */
status = in_8(&i2c->sts);
udelay(10);
i--;
} while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR) &&
(i > 0));
if (status & IIC_STS_ERR) {
result = IIC_NOK;
status = in_8(&i2c->extsts);
/* Lost arbitration? */
if (status & IIC_EXTSTS_LA)
result = IIC_NOK_LA;
/* Incomplete transfer? */
if (status & IIC_EXTSTS_ICT)
result = IIC_NOK_ICT;
/* Transfer aborted? */
if (status & IIC_EXTSTS_XFRA)
result = IIC_NOK_XFRA;
/* Is bus free?
* If error happened during combined xfer
* IIC interface is usually stuck in some strange
* state without a valid stop condition.
* Brute, but working: generate stop, then soft reset.
*/
if ((status & IIC_EXTSTS_BCS_MASK)
!= IIC_EXTSTS_BCS_FREE){
u8 mdcntl = in_8(&i2c->mdcntl);
/* Generate valid stop condition */
out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST);
out_8(&i2c->directcntl, IIC_DIRCNTL_SCC);
udelay(10);
out_8(&i2c->directcntl,
IIC_DIRCNTL_SCC | IIC_DIRCNTL_SDAC);
out_8(&i2c->xtcntlss, 0);
ppc4xx_i2c_init(adap, (mdcntl & IIC_MDCNTL_FSM)
? 400000 : 100000, 0);
}
} else if ( status & IIC_STS_PT) {
result = IIC_NOK_TOUT;
}
/* Command is reading => get buffer */
if ((reading) && (result == IIC_OK)) {
/* Are there data in buffer */
if (status & IIC_STS_MDBS) {
/*
* even if we have data we have to wait 4OPB
* clocks for it to hit the front of the FIFO,
* after that we can just read. We should check
* XFCNT here and if the FIFO is full there is
* no need to wait.
*/
udelay(1);
for (j = 0; j < bc; j++)
ptr[tran + j] = in_8(&i2c->mdbuf);
} else
result = IIC_NOK_DATA;
}
creg = 0;
tran += bc;
if (ptr == addr && tran == cnt) {
ptr = data;
cnt = data_len;
tran = 0;
reading = cmd_type;
}
}
return result;
}
static int ppc4xx_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar buf[1];
buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
return (_i2c_transfer(adap, 1, chip << 1, 0, 0, buf, 1) != 0);
}
static int ppc4xx_i2c_transfer(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len, int read)
{
uchar xaddr[4];
int ret;
if (alen > 4) {
printf("I2C: addr len %d not supported\n", alen);
return 1;
}
if (alen > 0) {
xaddr[0] = (addr >> 24) & 0xFF;
xaddr[1] = (addr >> 16) & 0xFF;
xaddr[2] = (addr >> 8) & 0xFF;
xaddr[3] = addr & 0xFF;
}
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
if (alen > 0)
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
ret = _i2c_transfer(adap, read, chip << 1, &xaddr[4 - alen], alen,
buffer, len);
if (ret) {
printf("I2C %s: failed %d\n", read ? "read" : "write", ret);
return 1;
}
return 0;
}
static int ppc4xx_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
return ppc4xx_i2c_transfer(adap, chip, addr, alen, buffer, len, 1);
}
static int ppc4xx_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
return ppc4xx_i2c_transfer(adap, chip, addr, alen, buffer, len, 0);
}
static unsigned int ppc4xx_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
if (speed != adap->speed)
return -1;
return speed;
}
/*
* Register ppc4xx i2c adapters
*/
#ifdef CONFIG_SYS_I2C_PPC4XX_CH0
U_BOOT_I2C_ADAP_COMPLETE(ppc4xx_0, ppc4xx_i2c_init, ppc4xx_i2c_probe,
ppc4xx_i2c_read, ppc4xx_i2c_write,
ppc4xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_PPC4XX_SPEED_0,
CONFIG_SYS_I2C_PPC4XX_SLAVE_0, 0)
#endif
#ifdef CONFIG_SYS_I2C_PPC4XX_CH1
U_BOOT_I2C_ADAP_COMPLETE(ppc4xx_1, ppc4xx_i2c_init, ppc4xx_i2c_probe,
ppc4xx_i2c_read, ppc4xx_i2c_write,
ppc4xx_i2c_set_bus_speed,
CONFIG_SYS_I2C_PPC4XX_SPEED_1,
CONFIG_SYS_I2C_PPC4XX_SLAVE_1, 1)
#endif

View File

@@ -0,0 +1,290 @@
/*
* drivers/i2c/rcar_i2c.c
*
* Copyright (C) 2013 Renesas Electronics Corporation
* Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <i2c.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
struct rcar_i2c {
u32 icscr;
u32 icmcr;
u32 icssr;
u32 icmsr;
u32 icsier;
u32 icmier;
u32 icccr;
u32 icsar;
u32 icmar;
u32 icrxdtxd;
u32 icccr2;
u32 icmpr;
u32 ichpr;
u32 iclpr;
};
#define MCR_MDBS 0x80 /* non-fifo mode switch */
#define MCR_FSCL 0x40 /* override SCL pin */
#define MCR_FSDA 0x20 /* override SDA pin */
#define MCR_OBPC 0x10 /* override pins */
#define MCR_MIE 0x08 /* master if enable */
#define MCR_TSBE 0x04
#define MCR_FSB 0x02 /* force stop bit */
#define MCR_ESG 0x01 /* en startbit gen. */
#define MSR_MASK 0x7f
#define MSR_MNR 0x40 /* nack received */
#define MSR_MAL 0x20 /* arbitration lost */
#define MSR_MST 0x10 /* sent a stop */
#define MSR_MDE 0x08
#define MSR_MDT 0x04
#define MSR_MDR 0x02
#define MSR_MAT 0x01 /* slave addr xfer done */
static const struct rcar_i2c *i2c_dev[CONFIF_SYS_RCAR_I2C_NUM_CONTROLLERS] = {
(struct rcar_i2c *)CONFIG_SYS_RCAR_I2C0_BASE,
(struct rcar_i2c *)CONFIG_SYS_RCAR_I2C1_BASE,
(struct rcar_i2c *)CONFIG_SYS_RCAR_I2C2_BASE,
(struct rcar_i2c *)CONFIG_SYS_RCAR_I2C3_BASE,
};
static void rcar_i2c_raw_rw_common(struct rcar_i2c *dev, u8 chip, uint addr)
{
/* set slave address */
writel(chip << 1, &dev->icmar);
/* set register address */
writel(addr, &dev->icrxdtxd);
/* clear status */
writel(0, &dev->icmsr);
/* start master send */
writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr);
while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDE))
!= (MSR_MAT | MSR_MDE))
udelay(10);
/* clear ESG */
writel(MCR_MDBS | MCR_MIE, &dev->icmcr);
/* start SCLclk */
writel(~(MSR_MAT | MSR_MDE), &dev->icmsr);
while (!(readl(&dev->icmsr) & MSR_MDE))
udelay(10);
}
static void rcar_i2c_raw_rw_finish(struct rcar_i2c *dev)
{
while (!(readl(&dev->icmsr) & MSR_MST))
udelay(10);
writel(0, &dev->icmcr);
}
static int
rcar_i2c_raw_write(struct rcar_i2c *dev, u8 chip, uint addr, u8 *val, int size)
{
rcar_i2c_raw_rw_common(dev, chip, addr);
/* set send date */
writel(*val, &dev->icrxdtxd);
/* start SCLclk */
writel(~MSR_MDE, &dev->icmsr);
while (!(readl(&dev->icmsr) & MSR_MDE))
udelay(10);
/* set stop condition */
writel(MCR_MDBS | MCR_MIE | MCR_FSB, &dev->icmcr);
/* start SCLclk */
writel(~MSR_MDE, &dev->icmsr);
rcar_i2c_raw_rw_finish(dev);
return 0;
}
static u8
rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr)
{
u8 ret;
rcar_i2c_raw_rw_common(dev, chip, addr);
/* set slave address, receive */
writel((chip << 1) | 1, &dev->icmar);
/* start master receive */
writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr);
/* clear status */
writel(0, &dev->icmsr);
while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDR))
!= (MSR_MAT | MSR_MDR))
udelay(10);
/* clear ESG */
writel(MCR_MDBS | MCR_MIE, &dev->icmcr);
/* prepare stop condition */
writel(MCR_MDBS | MCR_MIE | MCR_FSB, &dev->icmcr);
/* start SCLclk */
writel(~(MSR_MAT | MSR_MDR), &dev->icmsr);
while (!(readl(&dev->icmsr) & MSR_MDR))
udelay(10);
/* get receive data */
ret = (u8)readl(&dev->icrxdtxd);
/* start SCLclk */
writel(~MSR_MDR, &dev->icmsr);
rcar_i2c_raw_rw_finish(dev);
return ret;
}
/*
* SCL = iicck / (20 + SCGD * 8 + F[(ticf + tr + intd) * iicck])
* iicck : I2C internal clock < 20 MHz
* ticf : I2C SCL falling time: 35 ns
* tr : I2C SCL rising time: 200 ns
* intd : LSI internal delay: I2C0: 50 ns I2C1-3: 5
* F[n] : n rounded up to an integer
*/
static u32 rcar_clock_gen(int i2c_no, u32 bus_speed)
{
u32 iicck, f, scl, scgd;
u32 intd = 5;
int bit = 0, cdf_width = 3;
for (bit = 0; bit < (1 << cdf_width); bit++) {
iicck = CONFIG_HP_CLK_FREQ / (1 + bit);
if (iicck < 20000000)
break;
}
if (bit > (1 << cdf_width)) {
puts("rcar-i2c: Can not get CDF\n");
return 0;
}
if (i2c_no == 0)
intd = 50;
f = (35 + 200 + intd) * (iicck / 1000000000);
for (scgd = 0; scgd < 0x40; scgd++) {
scl = iicck / (20 + (scgd * 8) + f);
if (scl <= bus_speed)
break;
}
if (scgd > 0x40) {
puts("rcar-i2c: Can not get SDGB\n");
return 0;
}
debug("%s: scl: %d\n", __func__, scl);
debug("%s: bit %x\n", __func__, bit);
debug("%s: scgd %x\n", __func__, scgd);
debug("%s: iccr %x\n", __func__, (scgd << (cdf_width) | bit));
return scgd << (cdf_width) | bit;
}
static void
rcar_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr];
u32 icccr = 0;
/* No i2c support prior to relocation */
if (!(gd->flags & GD_FLG_RELOC))
return;
/*
* reset slave mode.
* slave mode is not used on this driver
*/
writel(0, &dev->icsier);
writel(0, &dev->icsar);
writel(0, &dev->icscr);
writel(0, &dev->icssr);
/* reset master mode */
writel(0, &dev->icmier);
writel(0, &dev->icmcr);
writel(0, &dev->icmsr);
writel(0, &dev->icmar);
icccr = rcar_clock_gen(adap->hwadapnr, adap->speed);
if (icccr == 0)
puts("I2C: Init failed\n");
else
writel(icccr, &dev->icccr);
}
static int rcar_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, u8 *data, int len)
{
struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr];
int i;
for (i = 0; i < len; i++)
data[i] = rcar_i2c_raw_read(dev, chip, addr + i);
return 0;
}
static int rcar_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr,
int alen, u8 *data, int len)
{
struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr];
return rcar_i2c_raw_write(dev, chip, addr, data, len);
}
static int
rcar_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
return rcar_i2c_read(adap, dev, 0, 0, NULL, 0);
}
static unsigned int rcar_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
struct rcar_i2c *dev = (struct rcar_i2c *)i2c_dev[adap->hwadapnr];
u32 icccr;
int ret = 0;
rcar_i2c_raw_rw_finish(dev);
icccr = rcar_clock_gen(adap->hwadapnr, speed);
if (icccr == 0) {
puts("I2C: Init failed\n");
ret = -1;
} else {
writel(icccr, &dev->icccr);
}
return ret;
}
/*
* Register RCAR i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(rcar_0, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read,
rcar_i2c_write, rcar_i2c_set_bus_speed,
CONFIG_SYS_RCAR_I2C0_SPEED, 0, 0)
U_BOOT_I2C_ADAP_COMPLETE(rcar_1, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read,
rcar_i2c_write, rcar_i2c_set_bus_speed,
CONFIG_SYS_RCAR_I2C1_SPEED, 0, 1)
U_BOOT_I2C_ADAP_COMPLETE(rcar_2, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read,
rcar_i2c_write, rcar_i2c_set_bus_speed,
CONFIG_SYS_RCAR_I2C2_SPEED, 0, 2)
U_BOOT_I2C_ADAP_COMPLETE(rcar_3, rcar_i2c_init, rcar_i2c_probe, rcar_i2c_read,
rcar_i2c_write, rcar_i2c_set_bus_speed,
CONFIG_SYS_RCAR_I2C3_SPEED, 0, 3)

395
u-boot/drivers/i2c/rk_i2c.c Normal file
View File

@@ -0,0 +1,395 @@
/*
* (C) Copyright 2015 Google, Inc
*
* (C) Copyright 2008-2014 Rockchip Electronics
* Peter, Software Engineering, <superpeter.cai@gmail.com>.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/i2c.h>
#include <asm/arch/periph.h>
#include <dm/pinctrl.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
/* i2c timerout */
#define I2C_TIMEOUT_MS 100
#define I2C_RETRY_COUNT 3
/* rk i2c fifo max transfer bytes */
#define RK_I2C_FIFO_SIZE 32
struct rk_i2c {
struct clk clk;
struct i2c_regs *regs;
unsigned int speed;
};
static inline void rk_i2c_get_div(int div, int *divh, int *divl)
{
*divl = div / 2;
if (div % 2 == 0)
*divh = div / 2;
else
*divh = DIV_ROUND_UP(div, 2);
}
/*
* SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
* SCL = PCLK / SCLK Divisor
* i2c_rate = PCLK
*/
static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
{
uint32_t i2c_rate;
int div, divl, divh;
/* First get i2c rate from pclk */
i2c_rate = clk_get_rate(&i2c->clk);
div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
divh = 0;
divl = 0;
if (div >= 0)
rk_i2c_get_div(div, &divh, &divl);
writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
debug("rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
scl_rate);
debug("set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
debug("set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
}
static void rk_i2c_show_regs(struct i2c_regs *regs)
{
#ifdef DEBUG
uint i;
debug("i2c_con: 0x%08x\n", readl(&regs->con));
debug("i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
debug("i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
debug("i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
debug("i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
debug("i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
debug("i2c_ien: 0x%08x\n", readl(&regs->ien));
debug("i2c_ipd: 0x%08x\n", readl(&regs->ipd));
debug("i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
for (i = 0; i < 8; i++)
debug("i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
for (i = 0; i < 8; i++)
debug("i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
#endif
}
static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
{
struct i2c_regs *regs = i2c->regs;
ulong start;
debug("I2c Send Start bit.\n");
writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
writel(I2C_CON_EN | I2C_CON_START, &regs->con);
writel(I2C_STARTIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_STARTIPD) {
writel(I2C_STARTIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Send Start Bit Timeout\n");
rk_i2c_show_regs(regs);
return -ETIMEDOUT;
}
udelay(1);
}
return 0;
}
static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
{
struct i2c_regs *regs = i2c->regs;
ulong start;
debug("I2c Send Stop bit.\n");
writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
writel(I2C_CON_STOP, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_STOPIPD) {
writel(I2C_STOPIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Send Start Bit Timeout\n");
rk_i2c_show_regs(regs);
return -ETIMEDOUT;
}
udelay(1);
}
return 0;
}
static inline void rk_i2c_disable(struct rk_i2c *i2c)
{
writel(0, &i2c->regs->con);
}
static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
struct i2c_regs *regs = i2c->regs;
uchar *pbuf = buf;
uint bytes_remain_len = b_len;
uint bytes_xferred = 0;
uint words_xferred = 0;
ulong start;
uint con = 0;
uint rxdata;
uint i, j;
int err;
debug("rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
chip, reg, r_len, b_len);
err = rk_i2c_send_start_bit(i2c);
if (err)
return err;
writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
if (r_len == 0) {
writel(0, &regs->mrxraddr);
} else if (r_len < 4) {
writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
} else {
debug("I2C Read: addr len %d not supported\n", r_len);
return -EIO;
}
while (bytes_remain_len) {
if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX);
bytes_xferred = 32;
} else {
con = I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TRX) |
I2C_CON_LASTACK;
bytes_xferred = bytes_remain_len;
}
words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
writel(con, &regs->con);
writel(bytes_xferred, &regs->mrxcnt);
writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
writel(I2C_NAKRCVIPD, &regs->ipd);
err = -EREMOTEIO;
}
if (readl(&regs->ipd) & I2C_MBRFIPD) {
writel(I2C_MBRFIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Read Data Timeout\n");
err = -ETIMEDOUT;
rk_i2c_show_regs(regs);
goto i2c_exit;
}
udelay(1);
}
for (i = 0; i < words_xferred; i++) {
rxdata = readl(&regs->rxdata[i]);
debug("I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
for (j = 0; j < 4; j++) {
if ((i * 4 + j) == bytes_xferred)
break;
*pbuf++ = (rxdata >> (j * 8)) & 0xff;
}
}
bytes_remain_len -= bytes_xferred;
debug("I2C Read bytes_remain_len %d\n", bytes_remain_len);
}
i2c_exit:
rk_i2c_send_stop_bit(i2c);
rk_i2c_disable(i2c);
return err;
}
static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
uchar *buf, uint b_len)
{
struct i2c_regs *regs = i2c->regs;
int err;
uchar *pbuf = buf;
uint bytes_remain_len = b_len + r_len + 1;
uint bytes_xferred = 0;
uint words_xferred = 0;
ulong start;
uint txdata;
uint i, j;
debug("rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
chip, reg, r_len, b_len);
err = rk_i2c_send_start_bit(i2c);
if (err)
return err;
while (bytes_remain_len) {
if (bytes_remain_len > RK_I2C_FIFO_SIZE)
bytes_xferred = 32;
else
bytes_xferred = bytes_remain_len;
words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
for (i = 0; i < words_xferred; i++) {
txdata = 0;
for (j = 0; j < 4; j++) {
if ((i * 4 + j) == bytes_xferred)
break;
if (i == 0 && j == 0) {
txdata |= (chip << 1);
} else if (i == 0 && j <= r_len) {
txdata |= (reg &
(0xff << ((j - 1) * 8))) << 8;
} else {
txdata |= (*pbuf++)<<(j * 8);
}
writel(txdata, &regs->txdata[i]);
}
debug("I2c Write TXDATA[%d] = 0x%x\n", i, txdata);
}
writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
writel(bytes_xferred, &regs->mtxcnt);
writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
start = get_timer(0);
while (1) {
if (readl(&regs->ipd) & I2C_NAKRCVIPD) {
writel(I2C_NAKRCVIPD, &regs->ipd);
err = -EREMOTEIO;
}
if (readl(&regs->ipd) & I2C_MBTFIPD) {
writel(I2C_MBTFIPD, &regs->ipd);
break;
}
if (get_timer(start) > I2C_TIMEOUT_MS) {
debug("I2C Write Data Timeout\n");
err = -ETIMEDOUT;
rk_i2c_show_regs(regs);
goto i2c_exit;
}
udelay(1);
}
bytes_remain_len -= bytes_xferred;
debug("I2C Write bytes_remain_len %d\n", bytes_remain_len);
}
i2c_exit:
rk_i2c_send_stop_bit(i2c);
rk_i2c_disable(i2c);
return err;
}
static int rockchip_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct rk_i2c *i2c = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
msg->len);
} else {
ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
msg->len);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
int rockchip_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct rk_i2c *i2c = dev_get_priv(bus);
rk_i2c_set_clk(i2c, speed);
return 0;
}
static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus)
{
struct rk_i2c *priv = dev_get_priv(bus);
int ret;
ret = clk_get_by_index(bus, 0, &priv->clk);
if (ret < 0) {
debug("%s: Could not get clock for %s: %d\n", __func__,
bus->name, ret);
return ret;
}
return 0;
}
static int rockchip_i2c_probe(struct udevice *bus)
{
struct rk_i2c *priv = dev_get_priv(bus);
priv->regs = (void *)dev_get_addr(bus);
return 0;
}
static const struct dm_i2c_ops rockchip_i2c_ops = {
.xfer = rockchip_i2c_xfer,
.set_bus_speed = rockchip_i2c_set_bus_speed,
};
static const struct udevice_id rockchip_i2c_ids[] = {
{ .compatible = "rockchip,rk3288-i2c" },
{ }
};
U_BOOT_DRIVER(i2c_rockchip) = {
.name = "i2c_rockchip",
.id = UCLASS_I2C,
.of_match = rockchip_i2c_ids,
.ofdata_to_platdata = rockchip_i2c_ofdata_to_platdata,
.probe = rockchip_i2c_probe,
.priv_auto_alloc_size = sizeof(struct rk_i2c),
.ops = &rockchip_i2c_ops,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2012 Samsung Electronics
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _S3C24X0_I2C_H
#define _S3C24X0_I2C_H
struct s3c24x0_i2c {
u32 iiccon;
u32 iicstat;
u32 iicadd;
u32 iicds;
u32 iiclc;
};
struct exynos5_hsi2c {
u32 usi_ctl;
u32 usi_fifo_ctl;
u32 usi_trailing_ctl;
u32 usi_clk_ctl;
u32 usi_clk_slot;
u32 spi_ctl;
u32 uart_ctl;
u32 res1;
u32 usi_int_en;
u32 usi_int_stat;
u32 usi_modem_stat;
u32 usi_error_stat;
u32 usi_fifo_stat;
u32 usi_txdata;
u32 usi_rxdata;
u32 res2;
u32 usi_conf;
u32 usi_auto_conf;
u32 usi_timeout;
u32 usi_manual_cmd;
u32 usi_trans_status;
u32 usi_timing_hs1;
u32 usi_timing_hs2;
u32 usi_timing_hs3;
u32 usi_timing_fs1;
u32 usi_timing_fs2;
u32 usi_timing_fs3;
u32 usi_timing_sla;
u32 i2c_addr;
};
struct s3c24x0_i2c_bus {
bool active; /* port is active and available */
int node; /* device tree node */
int bus_num; /* i2c bus number */
struct s3c24x0_i2c *regs;
struct exynos5_hsi2c *hsregs;
int is_highspeed; /* High speed type, rather than I2C */
unsigned clock_frequency;
int id;
unsigned clk_cycle;
unsigned clk_div;
};
#endif /* _S3C24X0_I2C_H */

View File

@@ -0,0 +1,123 @@
/*
* Simulate an I2C port
*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <asm/test.h>
#include <dm/lists.h>
#include <dm/device-internal.h>
#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
struct sandbox_i2c_priv {
bool test_mode;
};
static int get_emul(struct udevice *dev, struct udevice **devp,
struct dm_i2c_ops **opsp)
{
struct dm_i2c_chip *plat;
struct udevice *child;
int ret;
*devp = NULL;
*opsp = NULL;
plat = dev_get_parent_platdata(dev);
if (!plat->emul) {
ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
false);
if (ret)
return ret;
for (device_find_first_child(dev, &child); child;
device_find_next_child(&child)) {
if (device_get_uclass_id(child) != UCLASS_I2C_EMUL)
continue;
ret = device_probe(child);
if (ret)
return ret;
break;
}
if (child)
plat->emul = child;
else
return -ENODEV;
}
*devp = plat->emul;
*opsp = i2c_get_ops(plat->emul);
return 0;
}
void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode)
{
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
priv->test_mode = test_mode;
}
static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus);
struct sandbox_i2c_priv *priv = dev_get_priv(bus);
struct dm_i2c_ops *ops;
struct udevice *emul, *dev;
bool is_read;
int ret;
/* Special test code to return success but with no emulation */
if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR)
return 0;
ret = i2c_get_chip(bus, msg->addr, 1, &dev);
if (ret)
return ret;
ret = get_emul(dev, &emul, &ops);
if (ret)
return ret;
if (priv->test_mode) {
/*
* For testing, don't allow writing above 100KHz for writes and
* 400KHz for reads.
*/
is_read = nmsgs > 1;
if (i2c->speed_hz > (is_read ? 400000 : 100000)) {
debug("%s: Max speed exceeded\n", __func__);
return -EINVAL;
}
}
return ops->xfer(emul, msg, nmsgs);
}
static const struct dm_i2c_ops sandbox_i2c_ops = {
.xfer = sandbox_i2c_xfer,
};
static const struct udevice_id sandbox_i2c_ids[] = {
{ .compatible = "sandbox,i2c" },
{ }
};
U_BOOT_DRIVER(i2c_sandbox) = {
.name = "i2c_sandbox",
.id = UCLASS_I2C,
.of_match = sandbox_i2c_ids,
.ops = &sandbox_i2c_ops,
.priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv),
};

308
u-boot/drivers/i2c/sh_i2c.c Normal file
View File

@@ -0,0 +1,308 @@
/*
* Copyright (C) 2011, 2013 Renesas Solutions Corp.
* Copyright (C) 2011, 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR;
/* Every register is 32bit aligned, but only 8bits in size */
#define ureg(name) u8 name; u8 __pad_##name##0; u16 __pad_##name##1;
struct sh_i2c {
ureg(icdr);
ureg(iccr);
ureg(icsr);
ureg(icic);
ureg(iccl);
ureg(icch);
};
#undef ureg
/* ICCR */
#define SH_I2C_ICCR_ICE (1 << 7)
#define SH_I2C_ICCR_RACK (1 << 6)
#define SH_I2C_ICCR_RTS (1 << 4)
#define SH_I2C_ICCR_BUSY (1 << 2)
#define SH_I2C_ICCR_SCP (1 << 0)
/* ICSR / ICIC */
#define SH_IC_BUSY (1 << 4)
#define SH_IC_TACK (1 << 2)
#define SH_IC_WAIT (1 << 1)
#define SH_IC_DTE (1 << 0)
#ifdef CONFIG_SH_I2C_8BIT
/* store 8th bit of iccl and icch in ICIC register */
#define SH_I2C_ICIC_ICCLB8 (1 << 7)
#define SH_I2C_ICIC_ICCHB8 (1 << 6)
#endif
static const struct sh_i2c *i2c_dev[CONFIG_SYS_I2C_SH_NUM_CONTROLLERS] = {
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE0,
#ifdef CONFIG_SYS_I2C_SH_BASE1
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE1,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE2
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE2,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE3
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE3,
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE4
(struct sh_i2c *)CONFIG_SYS_I2C_SH_BASE4,
#endif
};
static u16 iccl, icch;
#define IRQ_WAIT 1000
static void sh_irq_dte(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (SH_IC_DTE & readb(&dev->icsr))
break;
udelay(10);
}
}
static int sh_irq_dte_with_tack(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (SH_IC_DTE & readb(&dev->icsr))
break;
if (SH_IC_TACK & readb(&dev->icsr))
return -1;
udelay(10);
}
return 0;
}
static void sh_irq_busy(struct sh_i2c *dev)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (!(SH_IC_BUSY & readb(&dev->icsr)))
break;
udelay(10);
}
}
static int sh_i2c_set_addr(struct sh_i2c *dev, u8 chip, u8 addr, int stop)
{
u8 icic = SH_IC_TACK;
debug("%s: chip: %x, addr: %x iccl: %x, icch %x\n",
__func__, chip, addr, iccl, icch);
clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
setbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
writeb(iccl & 0xff, &dev->iccl);
writeb(icch & 0xff, &dev->icch);
#ifdef CONFIG_SH_I2C_8BIT
if (iccl > 0xff)
icic |= SH_I2C_ICIC_ICCLB8;
if (icch > 0xff)
icic |= SH_I2C_ICIC_ICCHB8;
#endif
writeb(icic, &dev->icic);
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
sh_irq_dte(dev);
clrbits_8(&dev->icsr, SH_IC_TACK);
writeb(chip << 1, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
return -1;
writeb(addr, &dev->icdr);
if (stop)
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
return -1;
return 0;
}
static void sh_i2c_finish(struct sh_i2c *dev)
{
writeb(0, &dev->icsr);
clrbits_8(&dev->iccr, SH_I2C_ICCR_ICE);
}
static int
sh_i2c_raw_write(struct sh_i2c *dev, u8 chip, uint addr, u8 val)
{
int ret = -1;
if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
goto exit0;
udelay(10);
writeb(val, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
writeb((SH_I2C_ICCR_ICE | SH_I2C_ICCR_RTS), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
sh_irq_busy(dev);
ret = 0;
exit0:
sh_i2c_finish(dev);
return ret;
}
static int sh_i2c_raw_read(struct sh_i2c *dev, u8 chip, u8 addr)
{
int ret = -1;
#if defined(CONFIG_SH73A0)
if (sh_i2c_set_addr(dev, chip, addr, 0) != 0)
goto exit0;
#else
if (sh_i2c_set_addr(dev, chip, addr, 1) != 0)
goto exit0;
udelay(100);
#endif
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RTS|SH_I2C_ICCR_BUSY), &dev->iccr);
sh_irq_dte(dev);
writeb(chip << 1 | 0x01, &dev->icdr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_SCP), &dev->iccr);
if (sh_irq_dte_with_tack(dev) != 0)
goto exit0;
ret = readb(&dev->icdr) & 0xff;
writeb((SH_I2C_ICCR_ICE|SH_I2C_ICCR_RACK), &dev->iccr);
readb(&dev->icdr); /* Dummy read */
sh_irq_busy(dev);
exit0:
sh_i2c_finish(dev);
return ret;
}
static void
sh_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
int num, denom, tmp;
/* No i2c support prior to relocation */
if (!(gd->flags & GD_FLG_RELOC))
return;
/*
* Calculate the value for iccl. From the data sheet:
* iccl = (p-clock / transfer-rate) * (L / (L + H))
* where L and H are the SCL low and high ratio.
*/
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_LOW;
denom = speed * (CONFIG_SH_I2C_DATA_HIGH + CONFIG_SH_I2C_DATA_LOW);
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
iccl = (u16)((num/denom) + 1);
else
iccl = (u16)(num/denom);
/* Calculate the value for icch. From the data sheet:
icch = (p clock / transfer rate) * (H / (L + H)) */
num = CONFIG_SH_I2C_CLOCK * CONFIG_SH_I2C_DATA_HIGH;
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
icch = (u16)((num/denom) + 1);
else
icch = (u16)(num/denom);
debug("clock: %d, speed %d, iccl: %x, icch: %x\n",
CONFIG_SH_I2C_CLOCK, speed, iccl, icch);
}
static int sh_i2c_read(struct i2c_adapter *adap, uint8_t chip,
uint addr, int alen, u8 *data, int len)
{
int ret, i;
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
for (i = 0; i < len; i++) {
ret = sh_i2c_raw_read(dev, chip, addr + i);
if (ret < 0)
return -1;
data[i] = ret & 0xff;
debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
}
return 0;
}
static int sh_i2c_write(struct i2c_adapter *adap, uint8_t chip, uint addr,
int alen, u8 *data, int len)
{
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
int i;
for (i = 0; i < len; i++) {
debug("%s: data[%d]: %02x\n", __func__, i, data[i]);
if (sh_i2c_raw_write(dev, chip, addr + i, data[i]) != 0)
return -1;
}
return 0;
}
static int
sh_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
u8 dummy[1];
return sh_i2c_read(adap, dev, 0, 0, dummy, sizeof dummy);
}
static unsigned int sh_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
struct sh_i2c *dev = (struct sh_i2c *)i2c_dev[adap->hwadapnr];
sh_i2c_finish(dev);
sh_i2c_init(adap, speed, 0);
return 0;
}
/*
* Register RCAR i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(sh_0, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED0, 0, 0)
#ifdef CONFIG_SYS_I2C_SH_BASE1
U_BOOT_I2C_ADAP_COMPLETE(sh_1, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED1, 0, 1)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE2
U_BOOT_I2C_ADAP_COMPLETE(sh_2, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED2, 0, 2)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE3
U_BOOT_I2C_ADAP_COMPLETE(sh_3, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED3, 0, 3)
#endif
#ifdef CONFIG_SYS_I2C_SH_BASE4
U_BOOT_I2C_ADAP_COMPLETE(sh_4, sh_i2c_init, sh_i2c_probe, sh_i2c_read,
sh_i2c_write, sh_i2c_set_bus_speed, CONFIG_SYS_I2C_SH_SPEED4, 0, 4)
#endif

View File

@@ -0,0 +1,374 @@
/*
* Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
* Copyright (C) 2012 Renesas Solutions Corp.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <asm/io.h>
struct sh_i2c {
u8 iccr1;
u8 iccr2;
u8 icmr;
u8 icier;
u8 icsr;
u8 sar;
u8 icdrt;
u8 icdrr;
u8 nf2cyc;
u8 __pad0;
u8 __pad1;
};
static struct sh_i2c *base;
static u8 iccr1_cks, nf2cyc;
/* ICCR1 */
#define SH_I2C_ICCR1_ICE (1 << 7)
#define SH_I2C_ICCR1_RCVD (1 << 6)
#define SH_I2C_ICCR1_MST (1 << 5)
#define SH_I2C_ICCR1_TRS (1 << 4)
#define SH_I2C_ICCR1_MTRS \
(SH_I2C_ICCR1_MST | SH_I2C_ICCR1_TRS)
/* ICCR1 */
#define SH_I2C_ICCR2_BBSY (1 << 7)
#define SH_I2C_ICCR2_SCP (1 << 6)
#define SH_I2C_ICCR2_SDAO (1 << 5)
#define SH_I2C_ICCR2_SDAOP (1 << 4)
#define SH_I2C_ICCR2_SCLO (1 << 3)
#define SH_I2C_ICCR2_IICRST (1 << 1)
#define SH_I2C_ICIER_TIE (1 << 7)
#define SH_I2C_ICIER_TEIE (1 << 6)
#define SH_I2C_ICIER_RIE (1 << 5)
#define SH_I2C_ICIER_NAKIE (1 << 4)
#define SH_I2C_ICIER_STIE (1 << 3)
#define SH_I2C_ICIER_ACKE (1 << 2)
#define SH_I2C_ICIER_ACKBR (1 << 1)
#define SH_I2C_ICIER_ACKBT (1 << 0)
#define SH_I2C_ICSR_TDRE (1 << 7)
#define SH_I2C_ICSR_TEND (1 << 6)
#define SH_I2C_ICSR_RDRF (1 << 5)
#define SH_I2C_ICSR_NACKF (1 << 4)
#define SH_I2C_ICSR_STOP (1 << 3)
#define SH_I2C_ICSR_ALOVE (1 << 2)
#define SH_I2C_ICSR_AAS (1 << 1)
#define SH_I2C_ICSR_ADZ (1 << 0)
#define IRQ_WAIT 1000
static void sh_i2c_send_stop(struct sh_i2c *base)
{
clrbits_8(&base->iccr2, SH_I2C_ICCR2_BBSY | SH_I2C_ICCR2_SCP);
}
static int check_icsr_bits(struct sh_i2c *base, u8 bits)
{
int i;
for (i = 0; i < IRQ_WAIT; i++) {
if (bits & readb(&base->icsr))
return 0;
udelay(10);
}
return 1;
}
static int check_stop(struct sh_i2c *base)
{
int ret = check_icsr_bits(base, SH_I2C_ICSR_STOP);
clrbits_8(&base->icsr, SH_I2C_ICSR_STOP);
return ret;
}
static int check_tend(struct sh_i2c *base, int stop)
{
int ret = check_icsr_bits(base, SH_I2C_ICSR_TEND);
if (stop) {
clrbits_8(&base->icsr, SH_I2C_ICSR_STOP);
sh_i2c_send_stop(base);
}
clrbits_8(&base->icsr, SH_I2C_ICSR_TEND);
return ret;
}
static int check_tdre(struct sh_i2c *base)
{
return check_icsr_bits(base, SH_I2C_ICSR_TDRE);
}
static int check_rdrf(struct sh_i2c *base)
{
return check_icsr_bits(base, SH_I2C_ICSR_RDRF);
}
static int check_bbsy(struct sh_i2c *base)
{
int i;
for (i = 0 ; i < IRQ_WAIT ; i++) {
if (!(SH_I2C_ICCR2_BBSY & readb(&base->iccr2)))
return 0;
udelay(10);
}
return 1;
}
static int check_ackbr(struct sh_i2c *base)
{
int i;
for (i = 0 ; i < IRQ_WAIT ; i++) {
if (!(SH_I2C_ICIER_ACKBR & readb(&base->icier)))
return 0;
udelay(10);
}
return 1;
}
static void sh_i2c_reset(struct sh_i2c *base)
{
setbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST);
udelay(100);
clrbits_8(&base->iccr2, SH_I2C_ICCR2_IICRST);
}
static int i2c_set_addr(struct sh_i2c *base, u8 id, u8 reg)
{
if (check_bbsy(base)) {
puts("i2c bus busy\n");
goto fail;
}
setbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS);
clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY);
writeb((id << 1), &base->icdrt);
if (check_tend(base, 0)) {
puts("TEND check fail...\n");
goto fail;
}
if (check_ackbr(base)) {
check_tend(base, 0);
sh_i2c_send_stop(base);
goto fail;
}
writeb(reg, &base->icdrt);
if (check_tdre(base)) {
puts("TDRE check fail...\n");
goto fail;
}
if (check_tend(base, 0)) {
puts("TEND check fail...\n");
goto fail;
}
return 0;
fail:
return 1;
}
static int
i2c_raw_write(struct sh_i2c *base, u8 id, u8 reg, u8 *val, int size)
{
int i;
if (i2c_set_addr(base, id, reg)) {
puts("Fail set slave address\n");
return 1;
}
for (i = 0; i < size; i++) {
writeb(val[i], &base->icdrt);
check_tdre(base);
}
check_tend(base, 1);
check_stop(base);
udelay(100);
clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS);
clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE);
sh_i2c_reset(base);
return 0;
}
static u8 i2c_raw_read(struct sh_i2c *base, u8 id, u8 reg)
{
u8 ret = 0;
if (i2c_set_addr(base, id, reg)) {
puts("Fail set slave address\n");
goto fail;
}
clrsetbits_8(&base->iccr2, SH_I2C_ICCR2_SCP, SH_I2C_ICCR2_BBSY);
writeb((id << 1) | 1, &base->icdrt);
if (check_tend(base, 0))
puts("TDRE check fail...\n");
clrsetbits_8(&base->iccr1, SH_I2C_ICCR1_TRS, SH_I2C_ICCR1_MST);
clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE);
setbits_8(&base->icier, SH_I2C_ICIER_ACKBT);
setbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD);
/* read data (dummy) */
ret = readb(&base->icdrr);
if (check_rdrf(base)) {
puts("check RDRF error\n");
goto fail;
}
clrbits_8(&base->icsr, SH_I2C_ICSR_STOP);
udelay(1000);
sh_i2c_send_stop(base);
if (check_stop(base)) {
puts("check STOP error\n");
goto fail;
}
clrbits_8(&base->iccr1, SH_I2C_ICCR1_MTRS);
clrbits_8(&base->icsr, SH_I2C_ICSR_TDRE);
/* data read */
ret = readb(&base->icdrr);
fail:
clrbits_8(&base->iccr1, SH_I2C_ICCR1_RCVD);
return ret;
}
#ifdef CONFIG_I2C_MULTI_BUS
static unsigned int current_bus;
/**
* i2c_set_bus_num - change active I2C bus
* @bus: bus index, zero based
* @returns: 0 on success, non-0 on failure
*/
int i2c_set_bus_num(unsigned int bus)
{
switch (bus) {
case 0:
base = (void *)CONFIG_SH_I2C_BASE0;
break;
case 1:
base = (void *)CONFIG_SH_I2C_BASE1;
break;
default:
printf("Bad bus: %d\n", bus);
return -1;
}
current_bus = bus;
return 0;
}
/**
* i2c_get_bus_num - returns index of active I2C bus
*/
unsigned int i2c_get_bus_num(void)
{
return current_bus;
}
#endif
void i2c_init(int speed, int slaveaddr)
{
#ifdef CONFIG_I2C_MULTI_BUS
current_bus = 0;
#endif
base = (struct sh_i2c *)CONFIG_SH_I2C_BASE0;
if (speed == 400000)
iccr1_cks = 0x07;
else
iccr1_cks = 0x0F;
nf2cyc = 1;
/* Reset */
sh_i2c_reset(base);
/* ICE enable and set clock */
writeb(SH_I2C_ICCR1_ICE | iccr1_cks, &base->iccr1);
writeb(nf2cyc, &base->nf2cyc);
}
/*
* i2c_read: - Read multiple bytes from an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be read
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to write the data
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_read(u8 chip, u32 addr, int alen, u8 *buffer, int len)
{
int i = 0;
for (i = 0; i < len; i++)
buffer[i] = i2c_raw_read(base, chip, addr + i);
return 0;
}
/*
* i2c_write: - Write multiple bytes to an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be written
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to find the data to be written
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int i2c_write(u8 chip, u32 addr, int alen, u8 *buffer, int len)
{
return i2c_raw_write(base, chip, addr, buffer, len);
}
/*
* i2c_probe: - Test if a chip answers for a given i2c address
*
* @chip: address of the chip which is searched for
* @return: 0 if a chip was found, -1 otherwhise
*/
int i2c_probe(u8 chip)
{
u8 byte;
return i2c_read(chip, 0, 0, &byte, 1);
}

View File

@@ -0,0 +1,531 @@
/*
* (C) Copyright 2009
* Heiko Schocher, DENX Software Engineering, hs@denx.de.
* Changes for multibus/multiadapter I2C support.
*
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* SPDX-License-Identifier: GPL-2.0+
*
* This has been changed substantially by Gerald Van Baren, Custom IDEAS,
* vanbaren@cideas.com. It was heavily influenced by LiMon, written by
* Neil Russell.
*/
#include <common.h>
#ifdef CONFIG_MPC8260 /* only valid for MPC8260 */
#include <ioports.h>
#include <asm/io.h>
#endif
#if defined(CONFIG_AVR32)
#include <asm/arch/portmux.h>
#endif
#if defined(CONFIG_AT91FAMILY)
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91_pio.h>
#ifdef CONFIG_ATMEL_LEGACY
#include <asm/arch/gpio.h>
#endif
#endif
#if defined(CONFIG_MPC852T) || defined(CONFIG_MPC866)
#include <asm/io.h>
#endif
#include <i2c.h>
#if defined(CONFIG_SOFT_I2C_GPIO_SCL)
# include <asm/gpio.h>
# ifndef I2C_GPIO_SYNC
# define I2C_GPIO_SYNC
# endif
# ifndef I2C_INIT
# define I2C_INIT \
do { \
gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \
gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \
} while (0)
# endif
# ifndef I2C_ACTIVE
# define I2C_ACTIVE do { } while (0)
# endif
# ifndef I2C_TRISTATE
# define I2C_TRISTATE do { } while (0)
# endif
# ifndef I2C_READ
# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA)
# endif
# ifndef I2C_SDA
# define I2C_SDA(bit) \
do { \
if (bit) \
gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \
else \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_SCL
# define I2C_SCL(bit) \
do { \
gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \
I2C_GPIO_SYNC; \
} while (0)
# endif
# ifndef I2C_DELAY
# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */
# endif
#endif
/* #define DEBUG_I2C */
DECLARE_GLOBAL_DATA_PTR;
#ifndef I2C_SOFT_DECLARATIONS
# if defined(CONFIG_MPC8260)
# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = \
ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT);
# elif defined(CONFIG_8xx)
# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = \
(immap_t *)CONFIG_SYS_IMMR;
# else
# define I2C_SOFT_DECLARATIONS
# endif
#endif
#if !defined(CONFIG_SYS_I2C_SOFT_SPEED)
#define CONFIG_SYS_I2C_SOFT_SPEED CONFIG_SYS_I2C_SPEED
#endif
#if !defined(CONFIG_SYS_I2C_SOFT_SLAVE)
#define CONFIG_SYS_I2C_SOFT_SLAVE CONFIG_SYS_I2C_SLAVE
#endif
/*-----------------------------------------------------------------------
* Definitions
*/
#define RETRIES 0
#define I2C_ACK 0 /* PD_SDA level to ack a byte */
#define I2C_NOACK 1 /* PD_SDA level to noack a byte */
#ifdef DEBUG_I2C
#define PRINTD(fmt,args...) do { \
printf (fmt ,##args); \
} while (0)
#else
#define PRINTD(fmt,args...)
#endif
/*-----------------------------------------------------------------------
* Local functions
*/
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
static void send_reset (void);
#endif
static void send_start (void);
static void send_stop (void);
static void send_ack (int);
static int write_byte (uchar byte);
static uchar read_byte (int);
#if !defined(CONFIG_SYS_I2C_INIT_BOARD)
/*-----------------------------------------------------------------------
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void send_reset(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
I2C_SCL(1);
I2C_SDA(1);
#ifdef I2C_INIT
I2C_INIT;
#endif
I2C_TRISTATE;
for(j = 0; j < 9; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
}
send_stop();
I2C_TRISTATE;
}
#endif
/*-----------------------------------------------------------------------
* START: High -> Low on SDA while SCL is High
*/
static void send_start(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_DELAY;
I2C_SDA(1);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* STOP: Low -> High on SDA while SCL is High
*/
static void send_stop(void)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(0);
I2C_ACTIVE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_SDA(1);
I2C_DELAY;
I2C_TRISTATE;
}
/*-----------------------------------------------------------------------
* ack should be I2C_ACK or I2C_NOACK
*/
static void send_ack(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
I2C_SDA(ack);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
I2C_SCL(0);
I2C_DELAY;
}
/*-----------------------------------------------------------------------
* Send 8 bits and look for an acknowledgement.
*/
static int write_byte(uchar data)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int j;
int nack;
I2C_ACTIVE;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(data & 0x80);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
data <<= 1;
}
/*
* Look for an <ACK>(negative logic) and return it.
*/
I2C_SCL(0);
I2C_DELAY;
I2C_SDA(1);
I2C_TRISTATE;
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
I2C_DELAY;
nack = I2C_READ;
I2C_SCL(0);
I2C_DELAY;
I2C_ACTIVE;
return(nack); /* not a nack is an ack */
}
/*-----------------------------------------------------------------------
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar read_byte(int ack)
{
I2C_SOFT_DECLARATIONS /* intentional without ';' */
int data;
int j;
/*
* Read 8 bits, MSB first.
*/
I2C_TRISTATE;
I2C_SDA(1);
data = 0;
for(j = 0; j < 8; j++) {
I2C_SCL(0);
I2C_DELAY;
I2C_SCL(1);
I2C_DELAY;
data <<= 1;
data |= I2C_READ;
I2C_DELAY;
}
send_ack(ack);
return(data);
}
/*-----------------------------------------------------------------------
* Initialization
*/
static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
#if defined(CONFIG_SYS_I2C_INIT_BOARD)
/* call board specific i2c bus reset routine before accessing the */
/* environment, which might be in a chip on that bus. For details */
/* about this problem see doc/I2C_Edge_Conditions. */
i2c_init_board();
#else
/*
* WARNING: Do NOT save speed in a static variable: if the
* I2C routines are called before RAM is initialized (to read
* the DIMM SPD, for instance), RAM won't be usable and your
* system will crash.
*/
send_reset ();
#endif
}
/*-----------------------------------------------------------------------
* Probe to see if a chip is present. Also good for checking for the
* completion of EEPROM writes since the chip stops responding until
* the write completes (typically 10mSec).
*/
static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
{
int rc;
/*
* perform 1 byte write transaction with just address byte
* (fake write)
*/
send_start();
rc = write_byte ((addr << 1) | 0);
send_stop();
return (rc ? 1 : 0);
}
/*-----------------------------------------------------------------------
* Read bytes
*/
static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
int shift;
PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
/*
* EEPROM chips that implement "address overflow" are ones
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
* address and the extra bits end up in the "chip address"
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
* four 256 byte chips.
*
* Note that we consider the length of the address field to
* still be one byte because the extra address bits are
* hidden in the chip address.
*/
chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
chip, addr);
#endif
/*
* Do the addressing portion of a write cycle to set the
* chip's address pointer. If the address length is zero,
* don't do the normal write cycle to set the address pointer,
* there is no address pointer in this chip.
*/
send_start();
if(alen > 0) {
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_read, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_read, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
/* Some I2C chips need a stop/start sequence here,
* other chips don't work with a full stop and need
* only a start. Default behaviour is to send the
* stop/start sequence.
*/
#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START
send_start();
#else
send_stop();
send_start();
#endif
}
/*
* Send the chip address again, this time for a read cycle.
* Then read the data. On the last byte, we do a NACK instead
* of an ACK(len == 0) to terminate the read.
*/
write_byte((chip << 1) | 1); /* read cycle */
while(len-- > 0) {
*buffer++ = read_byte(len == 0);
}
send_stop();
return(0);
}
/*-----------------------------------------------------------------------
* Write bytes
*/
static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
int shift, failures = 0;
PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
chip, addr, alen, buffer, len);
send_start();
if(write_byte(chip << 1)) { /* write cycle */
send_stop();
PRINTD("i2c_write, no chip responded %02X\n", chip);
return(1);
}
shift = (alen-1) * 8;
while(alen-- > 0) {
if(write_byte(addr >> shift)) {
PRINTD("i2c_write, address not <ACK>ed\n");
return(1);
}
shift -= 8;
}
while(len-- > 0) {
if(write_byte(*buffer++)) {
failures++;
}
}
send_stop();
return(failures);
}
/*
* Register soft i2c adapters
*/
U_BOOT_I2C_ADAP_COMPLETE(soft00, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
0)
#if defined(I2C_SOFT_DECLARATIONS2)
U_BOOT_I2C_ADAP_COMPLETE(soft01, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_2,
CONFIG_SYS_I2C_SOFT_SLAVE_2,
1)
#endif
#if defined(I2C_SOFT_DECLARATIONS3)
U_BOOT_I2C_ADAP_COMPLETE(soft02, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_3,
CONFIG_SYS_I2C_SOFT_SLAVE_3,
2)
#endif
#if defined(I2C_SOFT_DECLARATIONS4)
U_BOOT_I2C_ADAP_COMPLETE(soft03, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_4,
CONFIG_SYS_I2C_SOFT_SLAVE_4,
3)
#endif
#if defined(I2C_SOFT_DECLARATIONS5)
U_BOOT_I2C_ADAP_COMPLETE(soft04, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_5,
CONFIG_SYS_I2C_SOFT_SLAVE_5,
4)
#endif
#if defined(I2C_SOFT_DECLARATIONS6)
U_BOOT_I2C_ADAP_COMPLETE(soft05, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_6,
CONFIG_SYS_I2C_SOFT_SLAVE_6,
5)
#endif
#if defined(I2C_SOFT_DECLARATIONS7)
U_BOOT_I2C_ADAP_COMPLETE(soft06, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_7,
CONFIG_SYS_I2C_SOFT_SLAVE_7,
6)
#endif
#if defined(I2C_SOFT_DECLARATIONS8)
U_BOOT_I2C_ADAP_COMPLETE(soft07, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_8,
CONFIG_SYS_I2C_SOFT_SLAVE_8,
7)
#endif
#if defined(I2C_SOFT_DECLARATIONS9)
U_BOOT_I2C_ADAP_COMPLETE(soft08, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_9,
CONFIG_SYS_I2C_SOFT_SLAVE_9,
8)
#endif
#if defined(I2C_SOFT_DECLARATIONS10)
U_BOOT_I2C_ADAP_COMPLETE(soft09, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_10,
CONFIG_SYS_I2C_SOFT_SLAVE_10,
9)
#endif
#if defined(I2C_SOFT_DECLARATIONS11)
U_BOOT_I2C_ADAP_COMPLETE(soft10, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_11,
CONFIG_SYS_I2C_SOFT_SLAVE_11,
10)
#endif
#if defined(I2C_SOFT_DECLARATIONS12)
U_BOOT_I2C_ADAP_COMPLETE(soft11, soft_i2c_init, soft_i2c_probe,
soft_i2c_read, soft_i2c_write, NULL,
CONFIG_SYS_I2C_SOFT_SPEED_12,
CONFIG_SYS_I2C_SOFT_SLAVE_12,
11)
#endif

View File

@@ -0,0 +1,501 @@
/*
* 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 <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>
#include <asm/arch-tegra/tegra_i2c.h>
DECLARE_GLOBAL_DATA_PTR;
enum i2c_type {
TYPE_114,
TYPE_STD,
TYPE_DVC,
};
/* Information about i2c controller */
struct i2c_bus {
int id;
enum periph_id periph_id;
int speed;
int pinmux_config;
struct i2c_control *control;
struct i2c_ctlr *regs;
enum i2c_type type;
int inited; /* bus is inited */
};
static void set_packet_mode(struct i2c_bus *i2c_bus)
{
u32 config;
config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
if (i2c_bus->type == TYPE_DVC) {
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
writel(config, &dvc->cnfg);
} else {
writel(config, &i2c_bus->regs->cnfg);
/*
* program I2C_SL_CNFG.NEWSL to ENABLE. This fixes probe
* issues, i.e., some slaves may be wrongly detected.
*/
setbits_le32(&i2c_bus->regs->sl_cnfg, I2C_SL_CNFG_NEWSL_MASK);
}
}
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
reset_periph(i2c_bus->periph_id, 1);
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
if (!i2c_bus->speed)
return;
debug("%s: speed=%d\n", __func__, i2c_bus->speed);
/*
* Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
* 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);
if (i2c_bus->type == TYPE_114) {
/*
* T114 I2C went to a single clock source for standard/fast and
* HS clock speeds. The new clock rate setting calculation is:
* SCL = CLK_SOURCE.I2C /
* (CLK_MULT_STD_FAST_MODE * (I2C_CLK_DIV_STD_FAST_MODE+1) *
* I2C FREQUENCY DIVISOR) as per the T114 TRM (sec 30.3.1).
*
* NOTE: We do this here, after the initial clock/pll start,
* because if we read the clk_div reg before the controller
* is running, we hang, and we need it for the new calc.
*/
int clk_div_stdfst_mode = readl(&i2c_bus->regs->clk_div) >> 16;
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);
}
/* Reset I2C controller. */
i2c_reset_controller(i2c_bus);
/* Configure I2C controller. */
if (i2c_bus->type == TYPE_DVC) { /* only for DVC I2C */
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
}
static void send_packet_headers(
struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans,
u32 packet_id,
bool end_with_repeated_start)
{
u32 data;
/* prepare header1: Header size = 0 Protocol = I2C, pktType = 0 */
data = PROTOCOL_TYPE_I2C << PKT_HDR1_PROTOCOL_SHIFT;
data |= packet_id << PKT_HDR1_PKT_ID_SHIFT;
data |= i2c_bus->id << PKT_HDR1_CTLR_ID_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 1 sent (0x%x)\n", data);
/* prepare header2 */
data = (trans->num_bytes - 1) << PKT_HDR2_PAYLOAD_SIZE_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 2 sent (0x%x)\n", data);
/* prepare IO specific header: configure the slave address */
data = trans->address << PKT_HDR3_SLAVE_ADDR_SHIFT;
/* Enable Read if it is not a write transaction */
if (!(trans->flags & I2C_IS_WRITE))
data |= PKT_HDR3_READ_MODE_MASK;
if (end_with_repeated_start)
data |= PKT_HDR3_REPEAT_START_MASK;
/* Write I2C specific header */
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 3 sent (0x%x)\n", data);
}
static int wait_for_tx_fifo_empty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_EMPTY_CNT_MASK)
>> TX_FIFO_EMPTY_CNT_SHIFT;
if (count == I2C_FIFO_DEPTH)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_rx_fifo_notempty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_FULL_CNT_MASK)
>> TX_FIFO_FULL_CNT_SHIFT;
if (count)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_transfer_complete(struct i2c_control *control)
{
int int_status;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
int_status = readl(&control->int_status);
if (int_status & I2C_INT_NO_ACK_MASK)
return -int_status;
if (int_status & I2C_INT_ARBITRATION_LOST_MASK)
return -int_status;
if (int_status & I2C_INT_XFER_COMPLETE_MASK)
return 0;
udelay(10);
timeout_us -= 10;
}
return -1;
}
static int send_recv_packets(struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans)
{
struct i2c_control *control = i2c_bus->control;
u32 int_status;
u32 words;
u8 *dptr;
u32 local;
uchar last_bytes;
int error = 0;
int is_write = trans->flags & I2C_IS_WRITE;
/* clear status from previous transaction, XFER_COMPLETE, NOACK, etc. */
int_status = readl(&control->int_status);
writel(int_status, &control->int_status);
send_packet_headers(i2c_bus, trans, 1,
trans->flags & I2C_USE_REPEATED_START);
words = DIV_ROUND_UP(trans->num_bytes, 4);
last_bytes = trans->num_bytes & 3;
dptr = trans->buf;
while (words) {
u32 *wptr = (u32 *)dptr;
if (is_write) {
/* deal with word alignment */
if ((words == 1) && last_bytes) {
local = 0;
memcpy(&local, dptr, last_bytes);
} else if ((unsigned long)dptr & 3) {
memcpy(&local, dptr, sizeof(u32));
} else {
local = *wptr;
}
writel(local, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", local);
if (!wait_for_tx_fifo_empty(control)) {
error = -1;
goto exit;
}
} else {
if (!wait_for_rx_fifo_notempty(control)) {
error = -1;
goto exit;
}
/*
* for the last word, we read into our local buffer,
* in case that caller did not provide enough buffer.
*/
local = readl(&control->rx_fifo);
if ((words == 1) && last_bytes)
memcpy(dptr, (char *)&local, last_bytes);
else if ((unsigned long)dptr & 3)
memcpy(dptr, &local, sizeof(u32));
else
*wptr = local;
debug("pkt data received (0x%x)\n", local);
}
words--;
dptr += sizeof(u32);
}
if (wait_for_transfer_complete(control)) {
error = -1;
goto exit;
}
return 0;
exit:
/* error, reset the controller. */
i2c_reset_controller(i2c_bus);
return error;
}
static int tegra_i2c_write_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len, bool end_with_repeated_start)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr;
trans_info.buf = data;
trans_info.flags = I2C_IS_WRITE;
if (end_with_repeated_start)
trans_info.flags |= I2C_USE_REPEATED_START;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
static int tegra_i2c_read_data(struct i2c_bus *i2c_bus, u32 addr, u8 *data,
u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr | 1;
trans_info.buf = data;
trans_info.flags = 0;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(i2c_bus, &trans_info);
if (error)
debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
static int tegra_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct i2c_bus *i2c_bus = dev_get_priv(dev);
i2c_bus->speed = speed;
i2c_init_controller(i2c_bus);
return 0;
}
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;
bool is_dvc;
i2c_bus->id = dev->seq;
i2c_bus->type = dev_get_driver_data(dev);
i2c_bus->regs = (struct i2c_ctlr *)dev_get_addr(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.
*/
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
* work on Seaboard. It normally has no devices on it anyway.
* 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)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
if (i2c_bus->periph_id == -1)
return -EINVAL;
is_dvc = dev_get_driver_data(dev) == TYPE_DVC;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
} else {
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);
return 0;
}
/* i2c write version without the register address */
static int i2c_write_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
int len, bool end_with_repeated_start)
{
int rc;
debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
debug("write_data: ");
/* use rc for counter */
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_write_data(i2c_bus, chip << 1, buffer, len,
end_with_repeated_start);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
return rc;
}
/* i2c read version without the register address */
static int i2c_read_data(struct i2c_bus *i2c_bus, uchar chip, uchar *buffer,
int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_read_data(i2c_bus, chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
}
debug("i2c_read_data: ");
/* reuse rc for counter*/
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
return 0;
}
/* Probe to see if a chip is present. */
static int tegra_i2c_probe_chip(struct udevice *bus, uint chip_addr,
uint chip_flags)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
int rc;
u8 reg;
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra_i2c_write_data(i2c_bus, chip_addr << 1, &reg, sizeof(reg),
false);
return rc;
}
static int tegra_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
struct i2c_bus *i2c_bus = dev_get_priv(bus);
int ret;
debug("i2c_xfer: %d messages\n", nmsgs);
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
if (msg->flags & I2C_M_RD) {
ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret) {
debug("i2c_write: error sending\n");
return -EREMOTEIO;
}
}
return 0;
}
int tegra_i2c_get_dvc_bus(struct udevice **busp)
{
struct udevice *bus;
for (uclass_first_device(UCLASS_I2C, &bus);
bus;
uclass_next_device(&bus)) {
if (dev_get_driver_data(bus) == TYPE_DVC) {
*busp = bus;
return 0;
}
}
return -ENODEV;
}
static const struct dm_i2c_ops tegra_i2c_ops = {
.xfer = tegra_i2c_xfer,
.probe_chip = tegra_i2c_probe_chip,
.set_bus_speed = tegra_i2c_set_bus_speed,
};
static const struct udevice_id tegra_i2c_ids[] = {
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
{ .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
{ }
};
U_BOOT_DRIVER(i2c_tegra) = {
.name = "i2c_tegra",
.id = UCLASS_I2C,
.of_match = tegra_i2c_ids,
.probe = tegra_i2c_probe,
.priv_auto_alloc_size = sizeof(struct i2c_bus),
.ops = &tegra_i2c_ops,
};

View File

@@ -0,0 +1,273 @@
/*
* (C) Copyright 2004 Tundra Semiconductor Corp.
* Author: Alex Bounine
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <tsi108.h>
#if defined(CONFIG_CMD_I2C)
#define I2C_DELAY 100000
#undef DEBUG_I2C
#ifdef DEBUG_I2C
#define DPRINT(x) printf (x)
#else
#define DPRINT(x)
#endif
/* All functions assume that Tsi108 I2C block is the only master on the bus */
/* I2C read helper function */
void i2c_init(int speed, int slaveaddr)
{
/*
* The TSI108 has a fixed I2C clock rate and doesn't support slave
* operation. This function only exists as a stub to fit into the
* U-Boot I2C API.
*/
}
static int i2c_read_byte (
uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */
uchar chip_addr,/* I2C device address on the bus */
uint byte_addr, /* Byte address within I2C device */
uchar * buffer /* pointer to data buffer */
)
{
u32 temp;
u32 to_count = I2C_DELAY;
u32 op_status = TSI108_I2C_TIMEOUT_ERR;
u32 chan_offset = TSI108_I2C_OFFSET;
DPRINT (("I2C read_byte() %d 0x%02x 0x%02x\n",
i2c_chan, chip_addr, byte_addr));
if (0 != i2c_chan)
chan_offset = TSI108_I2C_SDRAM_OFFSET;
/* Check if I2C operation is in progress */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS |
I2C_CNTRL2_START))) {
/* Set device address and operation (read = 0) */
temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) |
((chip_addr >> 3) & 0x0F);
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
temp;
/* Issue the read command
* (at this moment all other parameters are 0
* (size = 1 byte, lane = 0)
*/
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
(I2C_CNTRL2_START);
/* Wait until operation completed */
do {
/* Read I2C operation status */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
(I2C_CNTRL2_I2C_CFGERR |
I2C_CNTRL2_I2C_TO_ERR))
) {
op_status = TSI108_I2C_SUCCESS;
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
chan_offset +
I2C_RD_DATA);
*buffer = (u8) (temp & 0xFF);
} else {
/* report HW error */
op_status = TSI108_I2C_IF_ERROR;
DPRINT (("I2C HW error reported: 0x%02x\n", temp));
}
break;
}
} while (to_count--);
} else {
op_status = TSI108_I2C_IF_BUSY;
DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
}
DPRINT (("I2C read_byte() status: 0x%02x\n", op_status));
return op_status;
}
/*
* I2C Read interface as defined in "include/i2c.h" :
* chip_addr: I2C chip address, range 0..127
* (to read from SPD channel EEPROM use (0xD0 ... 0xD7)
* NOTE: The bit 7 in the chip_addr serves as a channel select.
* This hack is for enabling "i2c sdram" command on Tsi108 boards
* without changes to common code. Used for I2C reads only.
* byte_addr: Memory or register address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Pointer to destination buffer for data to be read
* len: How many bytes to read
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_read (uchar chip_addr, uint byte_addr, int alen,
uchar * buffer, int len)
{
u32 op_status = TSI108_I2C_PARAM_ERR;
u32 i2c_if = 0;
/* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/
if (0xD0 == (chip_addr & ~0x07)) {
i2c_if = 1;
chip_addr &= 0x7F;
}
/* Check for valid I2C address */
if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
while (len--) {
op_status = i2c_read_byte(i2c_if, chip_addr, byte_addr++, buffer++);
if (TSI108_I2C_SUCCESS != op_status) {
DPRINT (("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len));
break;
}
}
}
DPRINT (("I2C read() status: 0x%02x\n", op_status));
return op_status;
}
/* I2C write helper function */
static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */
uint byte_addr, /* Byte address within I2C device */
uchar * buffer /* pointer to data buffer */
)
{
u32 temp;
u32 to_count = I2C_DELAY;
u32 op_status = TSI108_I2C_TIMEOUT_ERR;
/* Check if I2C operation is in progress */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
/* Place data into the I2C Tx Register */
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_TX_DATA) = (u32) * buffer;
/* Set device address and operation */
temp =
I2C_CNTRL1_I2CWRITE | (byte_addr << 16) |
((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F);
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL1) = temp;
/* Issue the write command (at this moment all other parameters
* are 0 (size = 1 byte, lane = 0)
*/
*(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
I2C_CNTRL2) = (I2C_CNTRL2_START);
op_status = TSI108_I2C_TIMEOUT_ERR;
/* Wait until operation completed */
do {
/* Read I2C operation status */
temp = *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
if (0 == (temp &
(I2C_CNTRL2_I2C_CFGERR |
I2C_CNTRL2_I2C_TO_ERR))) {
op_status = TSI108_I2C_SUCCESS;
} else {
/* report detected HW error */
op_status = TSI108_I2C_IF_ERROR;
DPRINT (("I2C HW error reported: 0x%02x\n", temp));
}
break;
}
} while (to_count--);
} else {
op_status = TSI108_I2C_IF_BUSY;
DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
}
return op_status;
}
/*
* I2C Write interface as defined in "include/i2c.h" :
* chip_addr: I2C chip address, range 0..127
* byte_addr: Memory or register address within the chip
* alen: Number of bytes to use for addr (typically 1, 2 for larger
* memories, 0 for register type devices with only one
* register)
* buffer: Pointer to data to be written
* len: How many bytes to write
*
* Returns: 0 on success, not 0 on failure
*/
int i2c_write (uchar chip_addr, uint byte_addr, int alen, uchar * buffer,
int len)
{
u32 op_status = TSI108_I2C_PARAM_ERR;
/* Check for valid I2C address */
if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
while (len--) {
op_status =
i2c_write_byte (chip_addr, byte_addr++, buffer++);
if (TSI108_I2C_SUCCESS != op_status) {
DPRINT (("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len));
break;
}
}
}
return op_status;
}
/*
* I2C interface function as defined in "include/i2c.h".
* Probe the given I2C chip address by reading single byte from offset 0.
* Returns 0 if a chip responded, not 0 on failure.
*/
int i2c_probe (uchar chip)
{
u32 tmp;
/*
* Try to read the first location of the chip.
* The Tsi108 HW doesn't support sending just the chip address
* and checkong for an <ACK> back.
*/
return i2c_read (chip, 0, 1, (uchar *)&tmp, 1);
}
#endif

View File

@@ -0,0 +1,311 @@
/*
* Driver for the Zynq-7000 PS I2C controller
* IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2)
*
* Author: Joe Hershberger <joe.hershberger@ni.com>
* Copyright (c) 2012 Joe Hershberger.
*
* Copyright (c) 2012-2013 Xilinx, Michal Simek
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <asm/io.h>
#include <i2c.h>
#include <asm/errno.h>
#include <asm/arch/hardware.h>
/* i2c register set */
struct zynq_i2c_registers {
u32 control;
u32 status;
u32 address;
u32 data;
u32 interrupt_status;
u32 transfer_size;
u32 slave_mon_pause;
u32 time_out;
u32 interrupt_mask;
u32 interrupt_enable;
u32 interrupt_disable;
};
/* Control register fields */
#define ZYNQ_I2C_CONTROL_RW 0x00000001
#define ZYNQ_I2C_CONTROL_MS 0x00000002
#define ZYNQ_I2C_CONTROL_NEA 0x00000004
#define ZYNQ_I2C_CONTROL_ACKEN 0x00000008
#define ZYNQ_I2C_CONTROL_HOLD 0x00000010
#define ZYNQ_I2C_CONTROL_SLVMON 0x00000020
#define ZYNQ_I2C_CONTROL_CLR_FIFO 0x00000040
#define ZYNQ_I2C_CONTROL_DIV_B_SHIFT 8
#define ZYNQ_I2C_CONTROL_DIV_B_MASK 0x00003F00
#define ZYNQ_I2C_CONTROL_DIV_A_SHIFT 14
#define ZYNQ_I2C_CONTROL_DIV_A_MASK 0x0000C000
/* Status register values */
#define ZYNQ_I2C_STATUS_RXDV 0x00000020
#define ZYNQ_I2C_STATUS_TXDV 0x00000040
#define ZYNQ_I2C_STATUS_RXOVF 0x00000080
#define ZYNQ_I2C_STATUS_BA 0x00000100
/* Interrupt register fields */
#define ZYNQ_I2C_INTERRUPT_COMP 0x00000001
#define ZYNQ_I2C_INTERRUPT_DATA 0x00000002
#define ZYNQ_I2C_INTERRUPT_NACK 0x00000004
#define ZYNQ_I2C_INTERRUPT_TO 0x00000008
#define ZYNQ_I2C_INTERRUPT_SLVRDY 0x00000010
#define ZYNQ_I2C_INTERRUPT_RXOVF 0x00000020
#define ZYNQ_I2C_INTERRUPT_TXOVF 0x00000040
#define ZYNQ_I2C_INTERRUPT_RXUNF 0x00000080
#define ZYNQ_I2C_INTERRUPT_ARBLOST 0x00000200
#define ZYNQ_I2C_FIFO_DEPTH 16
#define ZYNQ_I2C_TRANSFERT_SIZE_MAX 255 /* Controller transfer limit */
static struct zynq_i2c_registers *i2c_select(struct i2c_adapter *adap)
{
return adap->hwadapnr ?
/* Zynq PS I2C1 */
(struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR1 :
/* Zynq PS I2C0 */
(struct zynq_i2c_registers *)ZYNQ_I2C_BASEADDR0;
}
/* I2C init called by cmd_i2c when doing 'i2c reset'. */
static void zynq_i2c_init(struct i2c_adapter *adap, int requested_speed,
int slaveadd)
{
struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
/* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) |
(2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control);
/* Enable master mode, ack, and 7-bit addressing */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_MS |
ZYNQ_I2C_CONTROL_ACKEN | ZYNQ_I2C_CONTROL_NEA);
}
#ifdef DEBUG
static void zynq_i2c_debug_status(struct zynq_i2c_registers *zynq_i2c)
{
int int_status;
int status;
int_status = readl(&zynq_i2c->interrupt_status);
status = readl(&zynq_i2c->status);
if (int_status || status) {
debug("Status: ");
if (int_status & ZYNQ_I2C_INTERRUPT_COMP)
debug("COMP ");
if (int_status & ZYNQ_I2C_INTERRUPT_DATA)
debug("DATA ");
if (int_status & ZYNQ_I2C_INTERRUPT_NACK)
debug("NACK ");
if (int_status & ZYNQ_I2C_INTERRUPT_TO)
debug("TO ");
if (int_status & ZYNQ_I2C_INTERRUPT_SLVRDY)
debug("SLVRDY ");
if (int_status & ZYNQ_I2C_INTERRUPT_RXOVF)
debug("RXOVF ");
if (int_status & ZYNQ_I2C_INTERRUPT_TXOVF)
debug("TXOVF ");
if (int_status & ZYNQ_I2C_INTERRUPT_RXUNF)
debug("RXUNF ");
if (int_status & ZYNQ_I2C_INTERRUPT_ARBLOST)
debug("ARBLOST ");
if (status & ZYNQ_I2C_STATUS_RXDV)
debug("RXDV ");
if (status & ZYNQ_I2C_STATUS_TXDV)
debug("TXDV ");
if (status & ZYNQ_I2C_STATUS_RXOVF)
debug("RXOVF ");
if (status & ZYNQ_I2C_STATUS_BA)
debug("BA ");
debug("TS%d ", readl(&zynq_i2c->transfer_size));
debug("\n");
}
}
#endif
/* Wait for an interrupt */
static u32 zynq_i2c_wait(struct zynq_i2c_registers *zynq_i2c, u32 mask)
{
int timeout, int_status;
for (timeout = 0; timeout < 100; timeout++) {
udelay(100);
int_status = readl(&zynq_i2c->interrupt_status);
if (int_status & mask)
break;
}
#ifdef DEBUG
zynq_i2c_debug_status(zynq_i2c);
#endif
/* Clear interrupt status flags */
writel(int_status & mask, &zynq_i2c->interrupt_status);
return int_status & mask;
}
/*
* I2C probe called by cmd_i2c when doing 'i2c probe'.
* Begin read, nak data byte, end.
*/
static int zynq_i2c_probe(struct i2c_adapter *adap, u8 dev)
{
struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
/* Attempt to read a byte */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_RW);
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
writel(0xFF, &zynq_i2c->interrupt_status);
writel(dev, &zynq_i2c->address);
writel(1, &zynq_i2c->transfer_size);
return (zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP |
ZYNQ_I2C_INTERRUPT_NACK) &
ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT;
}
/*
* I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c
* Begin write, send address byte(s), begin read, receive data bytes, end.
*/
static int zynq_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
u32 status;
u32 i = 0;
u8 *cur_data = data;
struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
/* Check the hardware can handle the requested bytes */
if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX))
return -EINVAL;
/* Write the register address */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_HOLD);
/*
* Temporarily disable restart (by clearing hold)
* It doesn't seem to work.
*/
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
writel(0xFF, &zynq_i2c->interrupt_status);
if (alen) {
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
writel(dev, &zynq_i2c->address);
while (alen--)
writel(addr >> (8 * alen), &zynq_i2c->data);
/* Wait for the address to be sent */
if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
debug("Device acked address\n");
}
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_RW);
/* Start reading data */
writel(dev, &zynq_i2c->address);
writel(length, &zynq_i2c->transfer_size);
/* Wait for data */
do {
status = zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP |
ZYNQ_I2C_INTERRUPT_DATA);
if (!status) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
debug("Read %d bytes\n",
length - readl(&zynq_i2c->transfer_size));
for (; i < length - readl(&zynq_i2c->transfer_size); i++)
*(cur_data++) = readl(&zynq_i2c->data);
} while (readl(&zynq_i2c->transfer_size) != 0);
/* All done... release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
#ifdef DEBUG
zynq_i2c_debug_status(zynq_i2c);
#endif
return 0;
}
/*
* I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c
* Begin write, send address byte(s), send data bytes, end.
*/
static int zynq_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr,
int alen, u8 *data, int length)
{
u8 *cur_data = data;
struct zynq_i2c_registers *zynq_i2c = i2c_select(adap);
/* Write the register address */
setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO |
ZYNQ_I2C_CONTROL_HOLD);
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW);
writel(0xFF, &zynq_i2c->interrupt_status);
writel(dev, &zynq_i2c->address);
if (alen) {
while (alen--)
writel(addr >> (8 * alen), &zynq_i2c->data);
/* Start the tranfer */
if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
debug("Device acked address\n");
}
while (length--) {
writel(*(cur_data++), &zynq_i2c->data);
if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) {
if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) {
/* Release the bus */
clrbits_le32(&zynq_i2c->control,
ZYNQ_I2C_CONTROL_HOLD);
return -ETIMEDOUT;
}
}
}
/* All done... release the bus */
clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD);
/* Wait for the address and data to be sent */
if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP))
return -ETIMEDOUT;
return 0;
}
static unsigned int zynq_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
{
if (speed != 1000000)
return -EINVAL;
return 0;
}
#ifdef CONFIG_ZYNQ_I2C0
U_BOOT_I2C_ADAP_COMPLETE(zynq_0, zynq_i2c_init, zynq_i2c_probe, zynq_i2c_read,
zynq_i2c_write, zynq_i2c_set_bus_speed,
CONFIG_SYS_I2C_ZYNQ_SPEED, CONFIG_SYS_I2C_ZYNQ_SLAVE,
0)
#endif
#ifdef CONFIG_ZYNQ_I2C1
U_BOOT_I2C_ADAP_COMPLETE(zynq_1, zynq_i2c_init, zynq_i2c_probe, zynq_i2c_read,
zynq_i2c_write, zynq_i2c_set_bus_speed,
CONFIG_SYS_I2C_ZYNQ_SPEED, CONFIG_SYS_I2C_ZYNQ_SLAVE,
1)
#endif