diff options
author | Tom Rini | 2023-02-13 09:57:35 -0500 |
---|---|---|
committer | Tom Rini | 2023-02-13 09:57:35 -0500 |
commit | d7bcd6ee409ae9c69dcc7b66462a4c86c165e6a9 (patch) | |
tree | 8602fd457e676c29c013272155aa23af7981dbc1 | |
parent | be9399b399f39c2cae49062ff2dacd1d05bb89c8 (diff) | |
parent | f536fda99fa2c1c88f68d8da54ed6233cec3532e (diff) |
Merge tag 'i2c-updates-for-v2023.04' of https://source.denx.de/u-boot/custodians/u-boot-i2c
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
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | arch/arm/dts/ast2600.dtsi | 1 | ||||
-rw-r--r-- | doc/device-tree-bindings/i2c/i2c-cdns.txt | 4 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 10 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/ast2600_i2c.c | 366 | ||||
-rw-r--r-- | drivers/i2c/ast2600_i2c.h | 120 | ||||
-rw-r--r-- | drivers/i2c/i2c-cdns.c | 30 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 2 |
9 files changed, 527 insertions, 13 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b9c505d5faa..6f53f9c2f6f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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> diff --git a/arch/arm/dts/ast2600.dtsi b/arch/arm/dts/ast2600.dtsi index 8d91eedc176..beabcf14f81 100644 --- a/arch/arm/dts/ast2600.dtsi +++ b/arch/arm/dts/ast2600.dtsi @@ -681,6 +681,7 @@ i2c: bus@1e78a000 { compatible = "simple-bus"; + reg = <0x1e78a000 0x1000>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x1e78a000 0x1000>; diff --git a/doc/device-tree-bindings/i2c/i2c-cdns.txt b/doc/device-tree-bindings/i2c/i2c-cdns.txt index 202e0b76266..eaff34a555b 100644 --- a/doc/device-tree-bindings/i2c/i2c-cdns.txt +++ b/doc/device-tree-bindings/i2c/i2c-cdns.txt @@ -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"; }; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 427074bff83..3279fef1eb0 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -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 diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 8a70b5ba88e..99545df2e55 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -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 diff --git a/drivers/i2c/ast2600_i2c.c b/drivers/i2c/ast2600_i2c.c new file mode 100644 index 00000000000..e566b01feac --- /dev/null +++ b/drivers/i2c/ast2600_i2c.c @@ -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), +}; diff --git a/drivers/i2c/ast2600_i2c.h b/drivers/i2c/ast2600_i2c.h new file mode 100644 index 00000000000..69699ba84c1 --- /dev/null +++ b/drivers/i2c/ast2600_i2c.h @@ -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_ */ diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c index 0da9f6f35a9..c1672ca18e1 100644 --- a/drivers/i2c/i2c-cdns.c +++ b/drivers/i2c/i2c-cdns.c @@ -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, ®s->address); start = 0; } - if (len && readl(®s->transfer_size) == CDNS_I2C_FIFO_DEPTH) { + if (len && readl(®s->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(®s->control, CDNS_I2C_CONTROL_HOLD); setbits_le32(®s->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(®s->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(®s->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(®s->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, ®s->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, ®s->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; } diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 86b9fb57c83..d501133a0c8 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -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); |