i2c updates for v2023.04

- add new i2c driver ast2600 from Ryan Chen

- i2c-cdns: make read fifo-depth configurable through device tree
  from Pei Yue Ho

- mxc i2c driver: print base address in hex, not in decimal
  from Fabio
This commit is contained in:
Tom Rini 2023-02-13 09:57:35 -05:00
commit d7bcd6ee40
9 changed files with 527 additions and 13 deletions

View file

@ -774,6 +774,12 @@ S: Maintained
F: drivers/pci/pcie_phytium.c
F: arch/arm/dts/phytium-durian.dts
ASPEED AST2600 I2C DRIVER
M: Ryan Chen <ryan_chen@aspeedtech.com>
R: Aspeed BMC SW team <BMC-SW@aspeedtech.com>
S: Maintained
F: drivers/i2c/ast2600_i2c.c
ASPEED FMC SPI DRIVER
M: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
M: Cédric Le Goater <clg@kaod.org>

View file

@ -681,6 +681,7 @@
i2c: bus@1e78a000 {
compatible = "simple-bus";
reg = <0x1e78a000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x1e78a000 0x1000>;

View file

@ -9,6 +9,9 @@ Required properties:
- interrupt-parent : Must be core interrupt controller
- clocks : Clock phandles (see clock bindings for details).
Optional properties:
- fifo-depth : To specify the FIFO depth of the controller.
Example:
i2c0: i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
@ -16,5 +19,6 @@ Example:
clocks = <&clkc 38>;
interrupts = <0 25 4>;
interrupt-parent = <&intc>;
fifo-depth = <32>;
status = "disabled";
};

View file

@ -221,6 +221,16 @@ config SYS_I2C_DW
controller is used in various SoCs, e.g. the ST SPEAr, Altera
SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs.
config SYS_I2C_AST2600
bool "AST2600 I2C Controller"
depends on DM_I2C && ARCH_ASPEED
help
Say yes here to select AST2600 I2C Host Controller. The driver
support AST2600 I2C new mode register. This I2C controller supports:
_Standard-mode (up to 100 kHz)
_Fast-mode (up to 400 kHz)
_Fast-mode Plus (up to 1 MHz)
config SYS_I2C_ASPEED
bool "Aspeed I2C Controller"
depends on DM_I2C && ARCH_ASPEED

View file

@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_$(SPL_)SYS_I2C_LEGACY) += i2c_core.o
obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o
obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o

366
drivers/i2c/ast2600_i2c.c Normal file
View file

@ -0,0 +1,366 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright ASPEED Technology Inc.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <log.h>
#include <regmap.h>
#include <reset.h>
#include <asm/io.h>
#include <linux/iopoll.h>
#include "ast2600_i2c.h"
/* Device private data */
struct ast2600_i2c_priv {
struct clk clk;
struct ast2600_i2c_regs *regs;
void __iomem *global;
};
static int ast2600_i2c_read_data(struct ast2600_i2c_priv *priv, u8 chip_addr,
u8 *buffer, size_t len, bool send_stop)
{
int rx_cnt, ret = 0;
u32 cmd, isr;
for (rx_cnt = 0; rx_cnt < len; rx_cnt++, buffer++) {
cmd = I2CM_PKT_EN | I2CM_PKT_ADDR(chip_addr) |
I2CM_RX_CMD;
if (!rx_cnt)
cmd |= I2CM_START_CMD;
if ((len - 1) == rx_cnt)
cmd |= I2CM_RX_CMD_LAST;
if (send_stop && ((len - 1) == rx_cnt))
cmd |= I2CM_STOP_CMD;
writel(cmd, &priv->regs->cmd_sts);
ret = readl_poll_timeout(&priv->regs->isr, isr,
isr & I2CM_PKT_DONE,
I2C_TIMEOUT_US);
if (ret)
return -ETIMEDOUT;
*buffer =
I2CC_GET_RX_BUFF(readl(&priv->regs->trx_buff));
writel(I2CM_PKT_DONE, &priv->regs->isr);
if (isr & I2CM_TX_NAK)
return -EREMOTEIO;
}
return 0;
}
static int ast2600_i2c_write_data(struct ast2600_i2c_priv *priv, u8 chip_addr,
u8 *buffer, size_t len, bool send_stop)
{
int tx_cnt, ret = 0;
u32 cmd, isr;
if (!len) {
cmd = I2CM_PKT_EN | I2CM_PKT_ADDR(chip_addr) |
I2CM_START_CMD;
writel(cmd, &priv->regs->cmd_sts);
ret = readl_poll_timeout(&priv->regs->isr, isr,
isr & I2CM_PKT_DONE,
I2C_TIMEOUT_US);
if (ret)
return -ETIMEDOUT;
writel(I2CM_PKT_DONE, &priv->regs->isr);
if (isr & I2CM_TX_NAK)
return -EREMOTEIO;
}
for (tx_cnt = 0; tx_cnt < len; tx_cnt++, buffer++) {
cmd = I2CM_PKT_EN | I2CM_PKT_ADDR(chip_addr);
cmd |= I2CM_TX_CMD;
if (!tx_cnt)
cmd |= I2CM_START_CMD;
if (send_stop && ((len - 1) == tx_cnt))
cmd |= I2CM_STOP_CMD;
writel(*buffer, &priv->regs->trx_buff);
writel(cmd, &priv->regs->cmd_sts);
ret = readl_poll_timeout(&priv->regs->isr, isr,
isr & I2CM_PKT_DONE,
I2C_TIMEOUT_US);
if (ret)
return -ETIMEDOUT;
writel(I2CM_PKT_DONE, &priv->regs->isr);
if (isr & I2CM_TX_NAK)
return -EREMOTEIO;
}
return 0;
}
static int ast2600_i2c_deblock(struct udevice *dev)
{
struct ast2600_i2c_priv *priv = dev_get_priv(dev);
u32 csr = readl(&priv->regs->cmd_sts);
u32 isr;
int ret;
/* reinit */
writel(0, &priv->regs->fun_ctrl);
/* Enable Master Mode. Assuming single-master */
writel(I2CC_BUS_AUTO_RELEASE | I2CC_MASTER_EN |
I2CC_MULTI_MASTER_DIS,
&priv->regs->fun_ctrl);
csr = readl(&priv->regs->cmd_sts);
if (!(csr & I2CC_SDA_LINE_STS) &&
(csr & I2CC_SCL_LINE_STS)) {
debug("Bus stuck (%x), attempting recovery\n", csr);
writel(I2CM_RECOVER_CMD_EN, &priv->regs->cmd_sts);
ret = readl_poll_timeout(&priv->regs->isr, isr,
isr & (I2CM_BUS_RECOVER_FAIL |
I2CM_BUS_RECOVER),
I2C_TIMEOUT_US);
writel(~0, &priv->regs->isr);
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int ast2600_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct ast2600_i2c_priv *priv = dev_get_priv(dev);
int ret;
if (readl(&priv->regs->trx_buff) & I2CC_BUS_BUSY_STS)
return -EREMOTEIO;
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD) {
debug("i2c_read: chip=0x%x, len=0x%x, flags=0x%x\n",
msg->addr, msg->len, msg->flags);
ret = ast2600_i2c_read_data(priv, msg->addr, msg->buf,
msg->len, (nmsgs == 1));
} else {
debug("i2c_write: chip=0x%x, len=0x%x, flags=0x%x\n",
msg->addr, msg->len, msg->flags);
ret = ast2600_i2c_write_data(priv, msg->addr, msg->buf,
msg->len, (nmsgs == 1));
}
if (ret) {
debug("%s: error (%d)\n", __func__, ret);
return -EREMOTEIO;
}
}
return 0;
}
static int ast2600_i2c_set_speed(struct udevice *dev, unsigned int speed)
{
struct ast2600_i2c_priv *priv = dev_get_priv(dev);
unsigned long base_clk1, base_clk2, base_clk3, base_clk4;
int multiply = 10;
int baseclk_idx;
u32 clk_div_reg;
u32 apb_clk;
u32 scl_low;
u32 scl_high;
int divisor;
int inc = 0;
u32 data;
debug("Setting speed for I2C%d to <%u>\n", dev->seq_, speed);
if (!speed) {
debug("No valid speed specified\n");
return -EINVAL;
}
apb_clk = clk_get_rate(&priv->clk);
clk_div_reg = readl(priv->global + I2CG_CLK_DIV_CTRL);
base_clk1 = (apb_clk * multiply) / (((GET_CLK1_DIV(clk_div_reg) + 2) * multiply) / 2);
base_clk2 = (apb_clk * multiply) / (((GET_CLK2_DIV(clk_div_reg) + 2) * multiply) / 2);
base_clk3 = (apb_clk * multiply) / (((GET_CLK3_DIV(clk_div_reg) + 2) * multiply) / 2);
base_clk4 = (apb_clk * multiply) / (((GET_CLK4_DIV(clk_div_reg) + 2) * multiply) / 2);
if ((apb_clk / speed) <= 32) {
baseclk_idx = 0;
divisor = DIV_ROUND_UP(apb_clk, speed);
} else if ((base_clk1 / speed) <= 32) {
baseclk_idx = 1;
divisor = DIV_ROUND_UP(base_clk1, speed);
} else if ((base_clk2 / speed) <= 32) {
baseclk_idx = 2;
divisor = DIV_ROUND_UP(base_clk2, speed);
} else if ((base_clk3 / speed) <= 32) {
baseclk_idx = 3;
divisor = DIV_ROUND_UP(base_clk3, speed);
} else {
baseclk_idx = 4;
divisor = DIV_ROUND_UP(base_clk4, speed);
inc = 0;
while ((divisor + inc) > 32) {
inc |= divisor & 0x1;
divisor >>= 1;
baseclk_idx++;
}
divisor += inc;
}
divisor = min_t(int, divisor, 32);
baseclk_idx &= 0xf;
scl_low = ((divisor * 9) / 16) - 1;
scl_low = min_t(u32, scl_low, 0xf);
scl_high = (divisor - scl_low - 2) & 0xf;
/* Divisor : Base Clock : tCKHighMin : tCK High : tCK Low */
data = ((scl_high - 1) << 20) | (scl_high << 16) | (scl_low << 12) |
baseclk_idx;
/* Set AC Timing */
writel(data, &priv->regs->ac_timing);
return 0;
}
static int ast2600_i2c_probe(struct udevice *dev)
{
struct ast2600_i2c_priv *priv = dev_get_priv(dev);
ofnode i2c_global_node;
/* find global base address */
i2c_global_node = ofnode_get_parent(dev_ofnode(dev));
priv->global = (void *)ofnode_get_addr(i2c_global_node);
if (IS_ERR(priv->global)) {
debug("%s(): can't get global\n", __func__);
return PTR_ERR(priv->global);
}
/* Reset device */
writel(0, &priv->regs->fun_ctrl);
/* Enable Master Mode. Assuming single-master */
writel(I2CC_BUS_AUTO_RELEASE | I2CC_MASTER_EN |
I2CC_MULTI_MASTER_DIS,
&priv->regs->fun_ctrl);
writel(0, &priv->regs->ier);
/* Clear Interrupt */
writel(~0, &priv->regs->isr);
return 0;
}
static int ast2600_i2c_of_to_plat(struct udevice *dev)
{
struct ast2600_i2c_priv *priv = dev_get_priv(dev);
int ret;
priv->regs = dev_read_addr_ptr(dev);
if (!priv->regs)
return -EINVAL;
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0) {
debug("%s: Can't get clock for %s: %d\n", __func__, dev->name,
ret);
return ret;
}
return 0;
}
static const struct dm_i2c_ops ast2600_i2c_ops = {
.xfer = ast2600_i2c_xfer,
.deblock = ast2600_i2c_deblock,
.set_bus_speed = ast2600_i2c_set_speed,
};
static const struct udevice_id ast2600_i2c_ids[] = {
{ .compatible = "aspeed,ast2600-i2c" },
{},
};
U_BOOT_DRIVER(ast2600_i2c) = {
.name = "ast2600_i2c",
.id = UCLASS_I2C,
.of_match = ast2600_i2c_ids,
.probe = ast2600_i2c_probe,
.of_to_plat = ast2600_i2c_of_to_plat,
.priv_auto = sizeof(struct ast2600_i2c_priv),
.ops = &ast2600_i2c_ops,
};
struct ast2600_i2c_global_priv {
void __iomem *regs;
struct reset_ctl reset;
};
/*
* APB clk : 100Mhz
* div : scl : baseclk [APB/((div/2) + 1)] : tBuf [1/bclk * 16]
* I2CG10[31:24] base clk4 for i2c auto recovery timeout counter (0xC6)
* I2CG10[23:16] base clk3 for Standard-mode (100Khz) min tBuf 4.7us
* 0x3c : 100.8Khz : 3.225Mhz : 4.96us
* 0x3d : 99.2Khz : 3.174Mhz : 5.04us
* 0x3e : 97.65Khz : 3.125Mhz : 5.12us
* 0x40 : 97.75Khz : 3.03Mhz : 5.28us
* 0x41 : 99.5Khz : 2.98Mhz : 5.36us (default)
* I2CG10[15:8] base clk2 for Fast-mode (400Khz) min tBuf 1.3us
* 0x12 : 400Khz : 10Mhz : 1.6us
* I2CG10[7:0] base clk1 for Fast-mode Plus (1Mhz) min tBuf 0.5us
* 0x08 : 1Mhz : 20Mhz : 0.8us
*/
static int aspeed_i2c_global_probe(struct udevice *dev)
{
struct ast2600_i2c_global_priv *i2c_global = dev_get_priv(dev);
void __iomem *regs;
int ret = 0;
i2c_global->regs = dev_read_addr_ptr(dev);
if (!i2c_global->regs)
return -EINVAL;
debug("%s(dev=%p)\n", __func__, dev);
regs = i2c_global->regs;
ret = reset_get_by_index(dev, 0, &i2c_global->reset);
if (ret) {
printf("%s(): Failed to get reset signal\n", __func__);
return ret;
}
reset_deassert(&i2c_global->reset);
writel(GLOBAL_INIT, regs + I2CG_CTRL);
writel(I2CCG_DIV_CTRL, regs + I2CG_CLK_DIV_CTRL);
return 0;
}
static const struct udevice_id aspeed_i2c_global_ids[] = {
{ .compatible = "aspeed,ast2600-i2c-global", },
{ }
};
U_BOOT_DRIVER(aspeed_i2c_global) = {
.name = "aspeed_i2c_global",
.id = UCLASS_MISC,
.of_match = aspeed_i2c_global_ids,
.probe = aspeed_i2c_global_probe,
.priv_auto = sizeof(struct ast2600_i2c_global_priv),
};

120
drivers/i2c/ast2600_i2c.h Normal file
View file

@ -0,0 +1,120 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright ASPEED Technology Inc.
*/
#ifndef __AST2600_I2C_H_
#define __AST2600_I2C_H_
struct ast2600_i2c_regs {
u32 fun_ctrl;
u32 ac_timing;
u32 trx_buff;
u32 icr;
u32 ier;
u32 isr;
u32 cmd_sts;
};
/* 0x00 : I2CC Master/Slave Function Control Register */
#define I2CC_SLAVE_ADDR_RX_EN BIT(20)
#define I2CC_MASTER_RETRY_MASK GENMASK(19, 18)
#define I2CC_MASTER_RETRY(x) (((x) & GENMASK(1, 0)) << 18)
#define I2CC_BUS_AUTO_RELEASE BIT(17)
#define I2CC_M_SDA_LOCK_EN BIT(16)
#define I2CC_MULTI_MASTER_DIS BIT(15)
#define I2CC_M_SCL_DRIVE_EN BIT(14)
#define I2CC_MSB_STS BIT(9)
#define I2CC_SDA_DRIVE_1T_EN BIT(8)
#define I2CC_M_SDA_DRIVE_1T_EN BIT(7)
#define I2CC_M_HIGH_SPEED_EN BIT(6)
/* reserved 5 : 2 */
#define I2CC_SLAVE_EN BIT(1)
#define I2CC_MASTER_EN BIT(0)
/* 0x04 : I2CD Clock and AC Timing Control Register #1 */
/* Base register value. These bits are always set by the driver. */
#define I2CD_CACTC_BASE 0xfff00300
#define I2CD_TCKHIGH_SHIFT 16
#define I2CD_TCKLOW_SHIFT 12
#define I2CD_THDDAT_SHIFT 10
#define I2CD_TO_DIV_SHIFT 8
#define I2CD_BASE_DIV_SHIFT 0
/* 0x08 : I2CC Master/Slave Transmit/Receive Byte Buffer Register */
#define I2CC_TX_DIR_MASK GENMASK(31, 29)
#define I2CC_SDA_OE BIT(28)
#define I2CC_SDA_O BIT(27)
#define I2CC_SCL_OE BIT(26)
#define I2CC_SCL_O BIT(25)
#define I2CC_SCL_LINE_STS BIT(18)
#define I2CC_SDA_LINE_STS BIT(17)
#define I2CC_BUS_BUSY_STS BIT(16)
#define I2CC_GET_RX_BUFF(x) (((x) >> 8) & GENMASK(7, 0))
/* 0x10 : I2CM Master Interrupt Control Register */
/* 0x14 : I2CM Master Interrupt Status Register */
#define I2CM_PKT_TIMEOUT BIT(18)
#define I2CM_PKT_ERROR BIT(17)
#define I2CM_PKT_DONE BIT(16)
#define I2CM_BUS_RECOVER_FAIL BIT(15)
#define I2CM_SDA_DL_TO BIT(14)
#define I2CM_BUS_RECOVER BIT(13)
#define I2CM_SMBUS_ALT BIT(12)
#define I2CM_SCL_LOW_TO BIT(6)
#define I2CM_ABNORMAL BIT(5)
#define I2CM_NORMAL_STOP BIT(4)
#define I2CM_ARBIT_LOSS BIT(3)
#define I2CM_RX_DONE BIT(2)
#define I2CM_TX_NAK BIT(1)
#define I2CM_TX_ACK BIT(0)
/* 0x18 : I2CM Master Command/Status Register */
#define I2CM_PKT_ADDR(x) (((x) & GENMASK(6, 0)) << 24)
#define I2CM_PKT_EN BIT(16)
#define I2CM_SDA_OE_OUT_DIR BIT(15)
#define I2CM_SDA_O_OUT_DIR BIT(14)
#define I2CM_SCL_OE_OUT_DIR BIT(13)
#define I2CM_SCL_O_OUT_DIR BIT(12)
#define I2CM_RECOVER_CMD_EN BIT(11)
#define I2CM_RX_DMA_EN BIT(9)
#define I2CM_TX_DMA_EN BIT(8)
/* Command Bit */
#define I2CM_RX_BUFF_EN BIT(7)
#define I2CM_TX_BUFF_EN BIT(6)
#define I2CM_STOP_CMD BIT(5)
#define I2CM_RX_CMD_LAST BIT(4)
#define I2CM_RX_CMD BIT(3)
#define I2CM_TX_CMD BIT(1)
#define I2CM_START_CMD BIT(0)
#define I2C_TIMEOUT_US 100000
/* I2C Global Register */
#define I2CG_ISR 0x00
#define I2CG_SLAVE_ISR 0x04
#define I2CG_OWNER 0x08
#define I2CG_CTRL 0x0C
#define I2CG_CLK_DIV_CTRL 0x10
#define I2CG_SLAVE_PKT_NAK BIT(4)
#define I2CG_M_S_SEPARATE_INTR BIT(3)
#define I2CG_CTRL_NEW_REG BIT(2)
#define I2CG_CTRL_NEW_CLK_DIV BIT(1)
#define GLOBAL_INIT \
(I2CG_SLAVE_PKT_NAK | \
I2CG_CTRL_NEW_REG | \
I2CG_CTRL_NEW_CLK_DIV)
#define I2CCG_DIV_CTRL 0xc6411208
#define GET_CLK1_DIV(x) ((x) & 0xff)
#define GET_CLK2_DIV(x) (((x) >> 8) & 0xff)
#define GET_CLK3_DIV(x) (((x) >> 16) & 0xff)
#define GET_CLK4_DIV(x) (((x) >> 24) & 0xff)
#endif /* __AST2600_I2C_H_ */

View file

@ -78,7 +78,7 @@ struct cdns_i2c_regs {
CDNS_I2C_INTERRUPT_RXUNF | \
CDNS_I2C_INTERRUPT_ARBLOST)
#define CDNS_I2C_FIFO_DEPTH 16
#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
#define CDNS_I2C_TRANSFER_SIZE_MAX 255 /* Controller transfer limit */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_TRANSFER_SIZE_MAX - 3)
@ -135,6 +135,7 @@ struct i2c_cdns_bus {
int hold_flag;
u32 quirks;
u32 fifo_depth;
};
struct cdns_i2c_platform_data {
@ -277,7 +278,7 @@ static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
writel(addr, &regs->address);
start = 0;
}
if (len && readl(&regs->transfer_size) == CDNS_I2C_FIFO_DEPTH) {
if (len && readl(&regs->transfer_size) == i2c_bus->fifo_depth) {
ret = cdns_i2c_wait(regs, CDNS_I2C_INTERRUPT_COMP |
CDNS_I2C_INTERRUPT_ARBLOST);
if (ret & CDNS_I2C_INTERRUPT_ARBLOST)
@ -310,9 +311,10 @@ static int cdns_i2c_write_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
return 0;
}
static inline bool cdns_is_hold_quirk(int hold_quirk, int curr_recv_count)
static inline bool cdns_is_hold_quirk(struct i2c_cdns_bus *i2c_bus, int hold_quirk,
int curr_recv_count)
{
return hold_quirk && (curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1);
return hold_quirk && (curr_recv_count == i2c_bus->fifo_depth + 1);
}
static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
@ -327,7 +329,7 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
curr_recv_count = recv_count;
/* Check for the message size against the FIFO depth */
if (recv_count > CDNS_I2C_FIFO_DEPTH)
if (recv_count > i2c_bus->fifo_depth)
setbits_le32(&regs->control, CDNS_I2C_CONTROL_HOLD);
setbits_le32(&regs->control, CDNS_I2C_CONTROL_CLR_FIFO |
@ -349,7 +351,7 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
while (recv_count && !is_arbitration_lost(regs)) {
while (readl(&regs->status) & CDNS_I2C_STATUS_RXDV) {
if (recv_count < CDNS_I2C_FIFO_DEPTH &&
if (recv_count < i2c_bus->fifo_depth &&
!i2c_bus->hold_flag) {
clrbits_le32(&regs->control,
CDNS_I2C_CONTROL_HOLD);
@ -358,27 +360,27 @@ static int cdns_i2c_read_data(struct i2c_cdns_bus *i2c_bus, u32 addr, u8 *data,
recv_count--;
curr_recv_count--;
if (cdns_is_hold_quirk(hold_quirk, curr_recv_count))
if (cdns_is_hold_quirk(i2c_bus, hold_quirk, curr_recv_count))
break;
}
if (cdns_is_hold_quirk(hold_quirk, curr_recv_count)) {
if (cdns_is_hold_quirk(i2c_bus, hold_quirk, curr_recv_count)) {
/* wait while fifo is full */
while (readl(&regs->transfer_size) !=
(curr_recv_count - CDNS_I2C_FIFO_DEPTH))
(curr_recv_count - i2c_bus->fifo_depth))
;
/*
* Check number of bytes to be received against maximum
* transfer size and update register accordingly.
*/
if ((recv_count - CDNS_I2C_FIFO_DEPTH) >
if ((recv_count - i2c_bus->fifo_depth) >
CDNS_I2C_TRANSFER_SIZE) {
writel(CDNS_I2C_TRANSFER_SIZE,
&regs->transfer_size);
curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
CDNS_I2C_FIFO_DEPTH;
i2c_bus->fifo_depth;
} else {
writel(recv_count - CDNS_I2C_FIFO_DEPTH,
writel(recv_count - i2c_bus->fifo_depth,
&regs->transfer_size);
curr_recv_count = recv_count;
}
@ -496,6 +498,10 @@ static int cdns_i2c_of_to_plat(struct udevice *dev)
return ret;
}
/* Update FIFO depth based on device tree entry */
i2c_bus->fifo_depth = dev_read_u32_default(dev, "fifo-depth",
CDNS_I2C_FIFO_DEPTH_DEFAULT);
return 0;
}

View file

@ -938,7 +938,7 @@ static int mxc_i2c_probe(struct udevice *bus)
* we can set pinmux here in probe function.
*/
debug("i2c : controller bus %d at %lu , speed %d: ",
debug("i2c : controller bus %d at 0x%lx , speed %d: ",
dev_seq(bus), i2c_bus->base,
i2c_bus->speed);