Merge branch 'i2c/for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "I2C has not so much stuff this time. Mostly driver enablement for new SoCs, some driver bugfixes, and some cleanups" * 'i2c/for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (35 commits) MAINTAINERS: add maintainer for Renesas RIIC driver i2c: sh_mobile: Remove dummy runtime PM callbacks i2c: uniphier-f: fix race condition when IRQ is cleared i2c: uniphier-f: fix occasional timeout error i2c: uniphier-f: make driver robust against concurrency i2c: i2c-qcom-geni: Simplify irq handler i2c: i2c-qcom-geni: Simplify tx/rx functions i2c: designware: Set IRQF_NO_SUSPEND flag for all BYT and CHT controllers i2c: mux: mlxcpld: simplify code to reach the adapter i2c: mux: ltc4306: simplify code to reach the adapter i2c: mux: pca954x: simplify code to reach the adapter i2c: core: remove level of indentation in i2c_transfer i2c: core: remove outdated DEBUG output i2c: zx2967: use core to detect 'no zero length' quirk i2c: tegra: use core to detect 'no zero length' quirk i2c: qup: use core to detect 'no zero length' quirk i2c: omap: use core to detect 'no zero length' quirk i2c: Convert to using %pOFn instead of device_node.name i2c: brcmstb: Allow enabling the driver on DSL SoCs eeprom: at24: fix unexpected timeout under high load ...
This commit is contained in:
commit
57dbde63f2
|
@ -3,6 +3,7 @@
|
|||
Required properties :
|
||||
|
||||
- compatible : should be "snps,designware-i2c"
|
||||
or "mscc,ocelot-i2c" with "snps,designware-i2c" for fallback
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : <IRQ> where IRQ is the interrupt number.
|
||||
|
||||
|
@ -11,8 +12,12 @@ Recommended properties :
|
|||
- clock-frequency : desired I2C bus clock frequency in Hz.
|
||||
|
||||
Optional properties :
|
||||
- reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
|
||||
time, named ICPU_CFG:TWI_DELAY in the datasheet.
|
||||
|
||||
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
|
||||
This option is only supported in hardware blocks version 1.11a or newer.
|
||||
This option is only supported in hardware blocks version 1.11a or newer and
|
||||
on Microsemi SoCs ("mscc,ocelot-i2c" compatible).
|
||||
|
||||
- i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
|
||||
This value which is by default 300ns is used to compute the tLOW period.
|
||||
|
|
|
@ -3,7 +3,9 @@ I2C for R-Car platforms
|
|||
Required properties:
|
||||
- compatible:
|
||||
"renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC.
|
||||
"renesas,i2c-r8a7744" if the device is a part of a R8A7744 SoC.
|
||||
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
||||
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
|
||||
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||
|
|
|
@ -5,6 +5,7 @@ Required properties:
|
|||
- "renesas,iic-r8a73a4" (R-Mobile APE6)
|
||||
- "renesas,iic-r8a7740" (R-Mobile A1)
|
||||
- "renesas,iic-r8a7743" (RZ/G1M)
|
||||
- "renesas,iic-r8a7744" (RZ/G1N)
|
||||
- "renesas,iic-r8a7745" (RZ/G1E)
|
||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
|
|
|
@ -12548,6 +12548,12 @@ S: Supported
|
|||
F: drivers/i2c/busses/i2c-rcar.c
|
||||
F: drivers/i2c/busses/i2c-sh_mobile.c
|
||||
|
||||
RENESAS RIIC DRIVER
|
||||
M: Chris Brandt <chris.brandt@renesas.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-riic.txt
|
||||
F: drivers/i2c/busses/i2c-riic.c
|
||||
|
||||
RENESAS USB PHY DRIVER
|
||||
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
L: linux-renesas-soc@vger.kernel.org
|
||||
|
|
|
@ -432,12 +432,13 @@ config I2C_BCM_KONA
|
|||
If you do not need KONA I2C interface, say N.
|
||||
|
||||
config I2C_BRCMSTB
|
||||
tristate "BRCM Settop I2C controller"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
|
||||
tristate "BRCM Settop/DSL I2C controller"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \
|
||||
COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Broadcom Settop SoCs.
|
||||
I2C interface on the Broadcom Settop/DSL SoCs.
|
||||
|
||||
If you do not need I2C interface, say N.
|
||||
|
||||
|
|
|
@ -82,6 +82,11 @@
|
|||
#define ASPEED_I2CD_INTR_RX_DONE BIT(2)
|
||||
#define ASPEED_I2CD_INTR_TX_NAK BIT(1)
|
||||
#define ASPEED_I2CD_INTR_TX_ACK BIT(0)
|
||||
#define ASPEED_I2CD_INTR_MASTER_ERRORS \
|
||||
(ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
|
||||
ASPEED_I2CD_INTR_SCL_TIMEOUT | \
|
||||
ASPEED_I2CD_INTR_ABNORMAL | \
|
||||
ASPEED_I2CD_INTR_ARBIT_LOSS)
|
||||
#define ASPEED_I2CD_INTR_ALL \
|
||||
(ASPEED_I2CD_INTR_SDA_DL_TIMEOUT | \
|
||||
ASPEED_I2CD_INTR_BUS_RECOVER_DONE | \
|
||||
|
@ -137,7 +142,8 @@ struct aspeed_i2c_bus {
|
|||
/* Synchronizes I/O mem access to base. */
|
||||
spinlock_t lock;
|
||||
struct completion cmd_complete;
|
||||
u32 (*get_clk_reg_val)(u32 divisor);
|
||||
u32 (*get_clk_reg_val)(struct device *dev,
|
||||
u32 divisor);
|
||||
unsigned long parent_clk_frequency;
|
||||
u32 bus_frequency;
|
||||
/* Transaction state. */
|
||||
|
@ -227,32 +233,26 @@ reset_out:
|
|||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
|
||||
static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
|
||||
{
|
||||
u32 command, irq_status, status_ack = 0;
|
||||
u32 command, irq_handled = 0;
|
||||
struct i2c_client *slave = bus->slave;
|
||||
bool irq_handled = true;
|
||||
u8 value;
|
||||
|
||||
if (!slave) {
|
||||
irq_handled = false;
|
||||
goto out;
|
||||
}
|
||||
if (!slave)
|
||||
return 0;
|
||||
|
||||
command = readl(bus->base + ASPEED_I2C_CMD_REG);
|
||||
irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
|
||||
/* Slave was requested, restart state machine. */
|
||||
if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {
|
||||
status_ack |= ASPEED_I2CD_INTR_SLAVE_MATCH;
|
||||
irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH;
|
||||
bus->slave_state = ASPEED_I2C_SLAVE_START;
|
||||
}
|
||||
|
||||
/* Slave is not currently active, irq was for someone else. */
|
||||
if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) {
|
||||
irq_handled = false;
|
||||
goto out;
|
||||
}
|
||||
if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
|
||||
return irq_handled;
|
||||
|
||||
dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
|
||||
irq_status, command);
|
||||
|
@ -269,31 +269,31 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
|
|||
bus->slave_state =
|
||||
ASPEED_I2C_SLAVE_WRITE_REQUESTED;
|
||||
}
|
||||
status_ack |= ASPEED_I2CD_INTR_RX_DONE;
|
||||
irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
|
||||
}
|
||||
|
||||
/* Slave was asked to stop. */
|
||||
if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {
|
||||
status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
|
||||
irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
|
||||
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
|
||||
}
|
||||
if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
|
||||
}
|
||||
if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
|
||||
switch (bus->slave_state) {
|
||||
case ASPEED_I2C_SLAVE_READ_REQUESTED:
|
||||
if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
|
||||
dev_err(bus->dev, "Unexpected ACK on read request.\n");
|
||||
bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
|
||||
|
||||
i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
|
||||
writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
|
||||
writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
|
||||
break;
|
||||
case ASPEED_I2C_SLAVE_READ_PROCESSED:
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
|
||||
dev_err(bus->dev,
|
||||
"Expected ACK after processed read.\n");
|
||||
|
@ -317,13 +317,6 @@ static bool aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus)
|
|||
break;
|
||||
}
|
||||
|
||||
if (status_ack != irq_status)
|
||||
dev_err(bus->dev,
|
||||
"irq handled != irq. expected %x, but was %x\n",
|
||||
irq_status, status_ack);
|
||||
writel(status_ack, bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
|
||||
out:
|
||||
return irq_handled;
|
||||
}
|
||||
#endif /* CONFIG_I2C_SLAVE */
|
||||
|
@ -380,21 +373,21 @@ static int aspeed_i2c_is_irq_error(u32 irq_status)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
||||
static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
|
||||
{
|
||||
u32 irq_status, status_ack = 0, command = 0;
|
||||
u32 irq_handled = 0, command = 0;
|
||||
struct i2c_msg *msg;
|
||||
u8 recv_byte;
|
||||
int ret;
|
||||
|
||||
irq_status = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
/* Ack all interrupt bits. */
|
||||
writel(irq_status, bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
|
||||
if (irq_status & ASPEED_I2CD_INTR_BUS_RECOVER_DONE) {
|
||||
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
|
||||
status_ack |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
|
||||
irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
|
||||
goto out_complete;
|
||||
} else {
|
||||
/* Master is not currently active, irq was for someone else. */
|
||||
if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
|
||||
goto out_no_complete;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -403,19 +396,22 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
|||
* INACTIVE state.
|
||||
*/
|
||||
ret = aspeed_i2c_is_irq_error(irq_status);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
|
||||
irq_status);
|
||||
bus->cmd_err = ret;
|
||||
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
|
||||
irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
/* We are in an invalid state; reset bus to a known state. */
|
||||
if (!bus->msgs) {
|
||||
dev_err(bus->dev, "bus in unknown state\n");
|
||||
dev_err(bus->dev, "bus in unknown state. irq_status: 0x%x\n",
|
||||
irq_status);
|
||||
bus->cmd_err = -EIO;
|
||||
if (bus->master_state != ASPEED_I2C_MASTER_STOP)
|
||||
if (bus->master_state != ASPEED_I2C_MASTER_STOP &&
|
||||
bus->master_state != ASPEED_I2C_MASTER_INACTIVE)
|
||||
aspeed_i2c_do_stop(bus);
|
||||
goto out_no_complete;
|
||||
}
|
||||
|
@ -428,13 +424,18 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
|||
*/
|
||||
if (bus->master_state == ASPEED_I2C_MASTER_START) {
|
||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
|
||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
|
||||
bus->cmd_err = -ENXIO;
|
||||
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
|
||||
goto out_complete;
|
||||
}
|
||||
pr_devel("no slave present at %02x\n", msg->addr);
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
bus->cmd_err = -ENXIO;
|
||||
aspeed_i2c_do_stop(bus);
|
||||
goto out_no_complete;
|
||||
}
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
if (msg->len == 0) { /* SMBUS_QUICK */
|
||||
aspeed_i2c_do_stop(bus);
|
||||
goto out_no_complete;
|
||||
|
@ -449,14 +450,14 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
|||
case ASPEED_I2C_MASTER_TX:
|
||||
if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_NAK)) {
|
||||
dev_dbg(bus->dev, "slave NACKed TX\n");
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
|
||||
goto error_and_stop;
|
||||
} else if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
|
||||
dev_err(bus->dev, "slave failed to ACK TX\n");
|
||||
goto error_and_stop;
|
||||
}
|
||||
status_ack |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
/* fallthrough intended */
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
/* fall through */
|
||||
case ASPEED_I2C_MASTER_TX_FIRST:
|
||||
if (bus->buf_index < msg->len) {
|
||||
bus->master_state = ASPEED_I2C_MASTER_TX;
|
||||
|
@ -472,13 +473,13 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
|||
/* RX may not have completed yet (only address cycle) */
|
||||
if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
|
||||
goto out_no_complete;
|
||||
/* fallthrough intended */
|
||||
/* fall through */
|
||||
case ASPEED_I2C_MASTER_RX:
|
||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
|
||||
dev_err(bus->dev, "master failed to RX\n");
|
||||
goto error_and_stop;
|
||||
}
|
||||
status_ack |= ASPEED_I2CD_INTR_RX_DONE;
|
||||
irq_handled |= ASPEED_I2CD_INTR_RX_DONE;
|
||||
|
||||
recv_byte = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;
|
||||
msg->buf[bus->buf_index++] = recv_byte;
|
||||
|
@ -506,11 +507,13 @@ static bool aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus)
|
|||
goto out_no_complete;
|
||||
case ASPEED_I2C_MASTER_STOP:
|
||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP))) {
|
||||
dev_err(bus->dev, "master failed to STOP\n");
|
||||
dev_err(bus->dev,
|
||||
"master failed to STOP. irq_status:0x%x\n",
|
||||
irq_status);
|
||||
bus->cmd_err = -EIO;
|
||||
/* Do not STOP as we have already tried. */
|
||||
} else {
|
||||
status_ack |= ASPEED_I2CD_INTR_NORMAL_STOP;
|
||||
irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
|
||||
}
|
||||
|
||||
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
|
||||
|
@ -540,33 +543,57 @@ out_complete:
|
|||
bus->master_xfer_result = bus->msgs_index + 1;
|
||||
complete(&bus->cmd_complete);
|
||||
out_no_complete:
|
||||
if (irq_status != status_ack)
|
||||
dev_err(bus->dev,
|
||||
"irq handled != irq. expected 0x%08x, but was 0x%08x\n",
|
||||
irq_status, status_ack);
|
||||
return !!irq_status;
|
||||
return irq_handled;
|
||||
}
|
||||
|
||||
static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct aspeed_i2c_bus *bus = dev_id;
|
||||
bool ret;
|
||||
u32 irq_received, irq_remaining, irq_handled;
|
||||
|
||||
spin_lock(&bus->lock);
|
||||
irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
/* Ack all interrupts except for Rx done */
|
||||
writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,
|
||||
bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
irq_remaining = irq_received;
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
if (aspeed_i2c_slave_irq(bus)) {
|
||||
dev_dbg(bus->dev, "irq handled by slave.\n");
|
||||
ret = true;
|
||||
goto out;
|
||||
/*
|
||||
* In most cases, interrupt bits will be set one by one, although
|
||||
* multiple interrupt bits could be set at the same time. It's also
|
||||
* possible that master interrupt bits could be set along with slave
|
||||
* interrupt bits. Each case needs to be handled using corresponding
|
||||
* handlers depending on the current state.
|
||||
*/
|
||||
if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
|
||||
irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
|
||||
irq_remaining &= ~irq_handled;
|
||||
if (irq_remaining)
|
||||
irq_handled |= aspeed_i2c_slave_irq(bus, irq_remaining);
|
||||
} else {
|
||||
irq_handled = aspeed_i2c_slave_irq(bus, irq_remaining);
|
||||
irq_remaining &= ~irq_handled;
|
||||
if (irq_remaining)
|
||||
irq_handled |= aspeed_i2c_master_irq(bus,
|
||||
irq_remaining);
|
||||
}
|
||||
#else
|
||||
irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
|
||||
#endif /* CONFIG_I2C_SLAVE */
|
||||
|
||||
ret = aspeed_i2c_master_irq(bus);
|
||||
irq_remaining &= ~irq_handled;
|
||||
if (irq_remaining)
|
||||
dev_err(bus->dev,
|
||||
"irq handled != irq. expected 0x%08x, but was 0x%08x\n",
|
||||
irq_received, irq_handled);
|
||||
|
||||
out:
|
||||
/* Ack Rx done */
|
||||
if (irq_received & ASPEED_I2CD_INTR_RX_DONE)
|
||||
writel(ASPEED_I2CD_INTR_RX_DONE,
|
||||
bus->base + ASPEED_I2C_INTR_STS_REG);
|
||||
spin_unlock(&bus->lock);
|
||||
return ret ? IRQ_HANDLED : IRQ_NONE;
|
||||
return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
|
@ -684,16 +711,27 @@ static const struct i2c_algorithm aspeed_i2c_algo = {
|
|||
#endif /* CONFIG_I2C_SLAVE */
|
||||
};
|
||||
|
||||
static u32 aspeed_i2c_get_clk_reg_val(u32 clk_high_low_max, u32 divisor)
|
||||
static u32 aspeed_i2c_get_clk_reg_val(struct device *dev,
|
||||
u32 clk_high_low_mask,
|
||||
u32 divisor)
|
||||
{
|
||||
u32 base_clk, clk_high, clk_low, tmp;
|
||||
u32 base_clk_divisor, clk_high_low_max, clk_high, clk_low, tmp;
|
||||
|
||||
/*
|
||||
* SCL_high and SCL_low represent a value 1 greater than what is stored
|
||||
* since a zero divider is meaningless. Thus, the max value each can
|
||||
* store is every bit set + 1. Since SCL_high and SCL_low are added
|
||||
* together (see below), the max value of both is the max value of one
|
||||
* them times two.
|
||||
*/
|
||||
clk_high_low_max = (clk_high_low_mask + 1) * 2;
|
||||
|
||||
/*
|
||||
* The actual clock frequency of SCL is:
|
||||
* SCL_freq = APB_freq / (base_freq * (SCL_high + SCL_low))
|
||||
* = APB_freq / divisor
|
||||
* where base_freq is a programmable clock divider; its value is
|
||||
* base_freq = 1 << base_clk
|
||||
* base_freq = 1 << base_clk_divisor
|
||||
* SCL_high is the number of base_freq clock cycles that SCL stays high
|
||||
* and SCL_low is the number of base_freq clock cycles that SCL stays
|
||||
* low for a period of SCL.
|
||||
|
@ -703,47 +741,59 @@ static u32 aspeed_i2c_get_clk_reg_val(u32 clk_high_low_max, u32 divisor)
|
|||
* SCL_low = clk_low + 1
|
||||
* Thus,
|
||||
* SCL_freq = APB_freq /
|
||||
* ((1 << base_clk) * (clk_high + 1 + clk_low + 1))
|
||||
* ((1 << base_clk_divisor) * (clk_high + 1 + clk_low + 1))
|
||||
* The documentation recommends clk_high >= clk_high_max / 2 and
|
||||
* clk_low >= clk_low_max / 2 - 1 when possible; this last constraint
|
||||
* gives us the following solution:
|
||||
*/
|
||||
base_clk = divisor > clk_high_low_max ?
|
||||
base_clk_divisor = divisor > clk_high_low_max ?
|
||||
ilog2((divisor - 1) / clk_high_low_max) + 1 : 0;
|
||||
tmp = (divisor + (1 << base_clk) - 1) >> base_clk;
|
||||
clk_low = tmp / 2;
|
||||
clk_high = tmp - clk_low;
|
||||
|
||||
if (clk_high)
|
||||
clk_high--;
|
||||
if (base_clk_divisor > ASPEED_I2CD_TIME_BASE_DIVISOR_MASK) {
|
||||
base_clk_divisor = ASPEED_I2CD_TIME_BASE_DIVISOR_MASK;
|
||||
clk_low = clk_high_low_mask;
|
||||
clk_high = clk_high_low_mask;
|
||||
dev_err(dev,
|
||||
"clamping clock divider: divider requested, %u, is greater than largest possible divider, %u.\n",
|
||||
divisor, (1 << base_clk_divisor) * clk_high_low_max);
|
||||
} else {
|
||||
tmp = (divisor + (1 << base_clk_divisor) - 1)
|
||||
>> base_clk_divisor;
|
||||
clk_low = tmp / 2;
|
||||
clk_high = tmp - clk_low;
|
||||
|
||||
if (clk_low)
|
||||
clk_low--;
|
||||
if (clk_high)
|
||||
clk_high--;
|
||||
|
||||
if (clk_low)
|
||||
clk_low--;
|
||||
}
|
||||
|
||||
|
||||
return ((clk_high << ASPEED_I2CD_TIME_SCL_HIGH_SHIFT)
|
||||
& ASPEED_I2CD_TIME_SCL_HIGH_MASK)
|
||||
| ((clk_low << ASPEED_I2CD_TIME_SCL_LOW_SHIFT)
|
||||
& ASPEED_I2CD_TIME_SCL_LOW_MASK)
|
||||
| (base_clk & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
|
||||
| (base_clk_divisor
|
||||
& ASPEED_I2CD_TIME_BASE_DIVISOR_MASK);
|
||||
}
|
||||
|
||||
static u32 aspeed_i2c_24xx_get_clk_reg_val(u32 divisor)
|
||||
static u32 aspeed_i2c_24xx_get_clk_reg_val(struct device *dev, u32 divisor)
|
||||
{
|
||||
/*
|
||||
* clk_high and clk_low are each 3 bits wide, so each can hold a max
|
||||
* value of 8 giving a clk_high_low_max of 16.
|
||||
*/
|
||||
return aspeed_i2c_get_clk_reg_val(16, divisor);
|
||||
return aspeed_i2c_get_clk_reg_val(dev, GENMASK(2, 0), divisor);
|
||||
}
|
||||
|
||||
static u32 aspeed_i2c_25xx_get_clk_reg_val(u32 divisor)
|
||||
static u32 aspeed_i2c_25xx_get_clk_reg_val(struct device *dev, u32 divisor)
|
||||
{
|
||||
/*
|
||||
* clk_high and clk_low are each 4 bits wide, so each can hold a max
|
||||
* value of 16 giving a clk_high_low_max of 32.
|
||||
*/
|
||||
return aspeed_i2c_get_clk_reg_val(32, divisor);
|
||||
return aspeed_i2c_get_clk_reg_val(dev, GENMASK(3, 0), divisor);
|
||||
}
|
||||
|
||||
/* precondition: bus.lock has been acquired. */
|
||||
|
@ -756,7 +806,7 @@ static int aspeed_i2c_init_clk(struct aspeed_i2c_bus *bus)
|
|||
clk_reg_val &= (ASPEED_I2CD_TIME_TBUF_MASK |
|
||||
ASPEED_I2CD_TIME_THDSTA_MASK |
|
||||
ASPEED_I2CD_TIME_TACST_MASK);
|
||||
clk_reg_val |= bus->get_clk_reg_val(divisor);
|
||||
clk_reg_val |= bus->get_clk_reg_val(bus->dev, divisor);
|
||||
writel(clk_reg_val, bus->base + ASPEED_I2C_AC_TIMING_REG1);
|
||||
writel(ASPEED_NO_TIMEOUT_CTRL, bus->base + ASPEED_I2C_AC_TIMING_REG2);
|
||||
|
||||
|
@ -872,7 +922,8 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
|
|||
if (!match)
|
||||
bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val;
|
||||
else
|
||||
bus->get_clk_reg_val = (u32 (*)(u32))match->data;
|
||||
bus->get_clk_reg_val = (u32 (*)(struct device *, u32))
|
||||
match->data;
|
||||
|
||||
/* Initialize the I2C adapter */
|
||||
spin_lock_init(&bus->lock);
|
||||
|
|
|
@ -164,7 +164,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
|
|||
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
|
||||
dev->acquire_lock = baytrail_i2c_acquire;
|
||||
dev->release_lock = baytrail_i2c_release;
|
||||
dev->pm_disabled = true;
|
||||
dev->shared_with_punit = true;
|
||||
|
||||
pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
|
||||
PM_QOS_DEFAULT_VALUE);
|
||||
|
|
|
@ -201,6 +201,8 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
|
|||
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
|
||||
dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
|
||||
dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
|
||||
} else if (dev->set_sda_hold_time) {
|
||||
dev->set_sda_hold_time(dev);
|
||||
} else if (dev->sda_hold_time) {
|
||||
dev_warn(dev->dev,
|
||||
"Hardware too old to adjust SDA hold time.\n");
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
* @pm_qos: pm_qos_request used while holding a hardware lock on the bus
|
||||
* @acquire_lock: function to acquire a hardware lock on the bus
|
||||
* @release_lock: function to release a hardware lock on the bus
|
||||
* @pm_disabled: true if power-management should be disabled for this i2c-bus
|
||||
* @shared_with_punit: true if this bus is shared with the SoCs PUNIT
|
||||
* @disable: function to disable the controller
|
||||
* @disable_int: function to disable all interrupts
|
||||
* @init: function to initialize the I2C hardware
|
||||
|
@ -225,6 +225,7 @@
|
|||
struct dw_i2c_dev {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
void __iomem *ext;
|
||||
struct completion cmd_complete;
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
|
@ -265,10 +266,11 @@ struct dw_i2c_dev {
|
|||
struct pm_qos_request pm_qos;
|
||||
int (*acquire_lock)(struct dw_i2c_dev *dev);
|
||||
void (*release_lock)(struct dw_i2c_dev *dev);
|
||||
bool pm_disabled;
|
||||
bool shared_with_punit;
|
||||
void (*disable)(struct dw_i2c_dev *dev);
|
||||
void (*disable_int)(struct dw_i2c_dev *dev);
|
||||
int (*init)(struct dw_i2c_dev *dev);
|
||||
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
|
||||
int mode;
|
||||
struct i2c_bus_recovery_info rinfo;
|
||||
};
|
||||
|
@ -276,8 +278,11 @@ struct dw_i2c_dev {
|
|||
#define ACCESS_SWAP 0x00000001
|
||||
#define ACCESS_16BIT 0x00000002
|
||||
#define ACCESS_INTR_MASK 0x00000004
|
||||
#define ACCESS_NO_IRQ_SUSPEND 0x00000008
|
||||
|
||||
#define MODEL_CHERRYTRAIL 0x00000100
|
||||
#define MODEL_MSCC_OCELOT 0x00000200
|
||||
#define MODEL_MASK 0x00000f00
|
||||
|
||||
u32 dw_readl(struct dw_i2c_dev *dev, int offset);
|
||||
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
|
||||
|
|
|
@ -709,7 +709,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
adap->dev.parent = dev->dev;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
if (dev->pm_disabled) {
|
||||
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
|
||||
irq_flags = IRQF_NO_SUSPEND;
|
||||
} else {
|
||||
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
|
||||
|
|
|
@ -85,10 +85,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
|
|||
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
|
||||
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
|
||||
const struct acpi_device_id *id;
|
||||
struct acpi_device *adev;
|
||||
const char *uid;
|
||||
|
||||
dev->adapter.nr = -1;
|
||||
dev->tx_fifo_depth = 32;
|
||||
|
@ -119,22 +115,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
|
|||
break;
|
||||
}
|
||||
|
||||
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
|
||||
if (id && id->driver_data)
|
||||
dev->flags |= (u32)id->driver_data;
|
||||
|
||||
if (acpi_bus_get_device(handle, &adev))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Cherrytrail I2C7 gets used for the PMIC which gets accessed
|
||||
* through ACPI opregions during late suspend / early resume
|
||||
* disable pm for it.
|
||||
*/
|
||||
uid = adev->pnp.unique_id;
|
||||
if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
|
||||
dev->pm_disabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -143,8 +123,8 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
|||
{ "INT33C3", 0 },
|
||||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "80860F41", 0 },
|
||||
{ "808622C1", MODEL_CHERRYTRAIL },
|
||||
{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
|
||||
{ "808622C1", ACCESS_NO_IRQ_SUSPEND | MODEL_CHERRYTRAIL },
|
||||
{ "AMD0010", ACCESS_INTR_MASK },
|
||||
{ "AMDI0010", ACCESS_INTR_MASK },
|
||||
{ "AMDI0510", 0 },
|
||||
|
@ -161,6 +141,51 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
|
||||
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
|
||||
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
|
||||
|
||||
static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
|
||||
{
|
||||
writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
|
||||
dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_i2c_of_configure(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_MSCC_OCELOT:
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
dev->ext = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (!IS_ERR(dev->ext))
|
||||
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dw_i2c_of_match[] = {
|
||||
{ .compatible = "snps,designware-i2c", },
|
||||
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
|
||||
#else
|
||||
static inline int dw_i2c_of_configure(struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
|
@ -221,7 +246,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
|
|||
{
|
||||
pm_runtime_disable(dev->dev);
|
||||
|
||||
if (dev->pm_disabled)
|
||||
if (dev->shared_with_punit)
|
||||
pm_runtime_put_noidle(dev->dev);
|
||||
}
|
||||
|
||||
|
@ -291,6 +316,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
else
|
||||
t->bus_freq_hz = 400000;
|
||||
|
||||
dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
dw_i2c_of_configure(pdev);
|
||||
|
||||
if (has_acpi_companion(&pdev->dev))
|
||||
dw_i2c_acpi_configure(pdev);
|
||||
|
||||
|
@ -348,7 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
|
||||
if (dev->pm_disabled)
|
||||
if (dev->shared_with_punit)
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
@ -393,14 +423,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id dw_i2c_of_match[] = {
|
||||
{ .compatible = "snps,designware-i2c", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dw_i2c_plat_prepare(struct device *dev)
|
||||
{
|
||||
|
@ -434,7 +456,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
|
|||
{
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (i_dev->pm_disabled)
|
||||
if (i_dev->shared_with_punit)
|
||||
return 0;
|
||||
|
||||
i_dev->disable(i_dev);
|
||||
|
@ -447,7 +469,7 @@ static int dw_i2c_plat_resume(struct device *dev)
|
|||
{
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (!i_dev->pm_disabled)
|
||||
if (!i_dev->shared_with_punit)
|
||||
i2c_dw_prepare_clk(i_dev, true);
|
||||
|
||||
i_dev->init(i_dev);
|
||||
|
|
|
@ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
u16 control_reg;
|
||||
u16 restart_flag = 0;
|
||||
u32 reg_4g_mode;
|
||||
u8 *dma_rd_buf = NULL;
|
||||
u8 *dma_wr_buf = NULL;
|
||||
dma_addr_t rpaddr = 0;
|
||||
dma_addr_t wpaddr = 0;
|
||||
int ret;
|
||||
|
@ -500,11 +502,19 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
if (i2c->op == I2C_MASTER_RD) {
|
||||
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||
writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
|
||||
rpaddr = dma_map_single(i2c->dev, msgs->buf,
|
||||
msgs->len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, rpaddr))
|
||||
|
||||
dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
|
||||
if (!dma_rd_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
|
||||
msgs->len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, rpaddr)) {
|
||||
i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
|
||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
|
||||
|
@ -515,11 +525,19 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
} else if (i2c->op == I2C_MASTER_WR) {
|
||||
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||
writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
|
||||
wpaddr = dma_map_single(i2c->dev, msgs->buf,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, wpaddr))
|
||||
|
||||
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
|
||||
if (!dma_wr_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, wpaddr)) {
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
|
||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
|
||||
|
@ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
} else {
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
|
||||
wpaddr = dma_map_single(i2c->dev, msgs->buf,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, wpaddr))
|
||||
|
||||
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
|
||||
if (!dma_wr_buf)
|
||||
return -ENOMEM;
|
||||
rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf,
|
||||
|
||||
wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, wpaddr)) {
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 0);
|
||||
if (!dma_rd_buf) {
|
||||
dma_unmap_single(i2c->dev, wpaddr,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
|
||||
(msgs + 1)->len,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(i2c->dev, rpaddr)) {
|
||||
dma_unmap_single(i2c->dev, wpaddr,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
|
||||
i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
if (i2c->op == I2C_MASTER_WR) {
|
||||
dma_unmap_single(i2c->dev, wpaddr,
|
||||
msgs->len, DMA_TO_DEVICE);
|
||||
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
|
||||
} else if (i2c->op == I2C_MASTER_RD) {
|
||||
dma_unmap_single(i2c->dev, rpaddr,
|
||||
msgs->len, DMA_FROM_DEVICE);
|
||||
|
||||
i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
|
||||
} else {
|
||||
dma_unmap_single(i2c->dev, wpaddr, msgs->len,
|
||||
DMA_TO_DEVICE);
|
||||
dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
|
||||
i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
|
|
|
@ -661,9 +661,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|||
dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
|
||||
msg->addr, msg->len, msg->flags, stop);
|
||||
|
||||
if (msg->len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
omap->receiver = !!(msg->flags & I2C_M_RD);
|
||||
omap_i2c_resize_fifo(omap, msg->len, omap->receiver);
|
||||
|
||||
|
@ -1179,6 +1176,10 @@ static const struct i2c_algorithm omap_i2c_algo = {
|
|||
.functionality = omap_i2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks omap_i2c_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct omap_i2c_bus_platform_data omap2420_pdata = {
|
||||
.rev = OMAP_I2C_IP_VERSION_1,
|
||||
|
@ -1453,6 +1454,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
|||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &omap_i2c_algo;
|
||||
adap->quirks = &omap_i2c_quirks;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
|
||||
|
|
|
@ -388,9 +388,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
|||
static int i2c_powermac_probe(struct platform_device *dev)
|
||||
{
|
||||
struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);
|
||||
struct device_node *parent = NULL;
|
||||
struct device_node *parent;
|
||||
struct i2c_adapter *adapter;
|
||||
const char *basename;
|
||||
int rc;
|
||||
|
||||
if (bus == NULL)
|
||||
|
@ -407,23 +406,25 @@ static int i2c_powermac_probe(struct platform_device *dev)
|
|||
parent = of_get_parent(pmac_i2c_get_controller(bus));
|
||||
if (parent == NULL)
|
||||
return -EINVAL;
|
||||
basename = parent->name;
|
||||
snprintf(adapter->name, sizeof(adapter->name), "%pOFn %d",
|
||||
parent,
|
||||
pmac_i2c_get_channel(bus));
|
||||
of_node_put(parent);
|
||||
break;
|
||||
case pmac_i2c_bus_pmu:
|
||||
basename = "pmu";
|
||||
snprintf(adapter->name, sizeof(adapter->name), "pmu %d",
|
||||
pmac_i2c_get_channel(bus));
|
||||
break;
|
||||
case pmac_i2c_bus_smu:
|
||||
/* This is not what we used to do but I'm fixing drivers at
|
||||
* the same time as this change
|
||||
*/
|
||||
basename = "smu";
|
||||
snprintf(adapter->name, sizeof(adapter->name), "smu %d",
|
||||
pmac_i2c_get_channel(bus));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
|
||||
pmac_i2c_get_channel(bus));
|
||||
of_node_put(parent);
|
||||
|
||||
platform_set_drvdata(dev, adapter);
|
||||
adapter->algo = &i2c_powermac_algorithm;
|
||||
|
|
|
@ -201,21 +201,23 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
|
|||
static irqreturn_t geni_i2c_irq(int irq, void *dev)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = dev;
|
||||
int j;
|
||||
void __iomem *base = gi2c->se.base;
|
||||
int j, p;
|
||||
u32 m_stat;
|
||||
u32 rx_st;
|
||||
u32 dm_tx_st;
|
||||
u32 dm_rx_st;
|
||||
u32 dma;
|
||||
u32 val;
|
||||
struct i2c_msg *cur;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gi2c->lock, flags);
|
||||
m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
|
||||
rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
|
||||
dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
|
||||
dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
|
||||
dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
|
||||
m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS);
|
||||
rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS);
|
||||
dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT);
|
||||
dm_rx_st = readl_relaxed(base + SE_DMA_RX_IRQ_STAT);
|
||||
dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
|
||||
cur = gi2c->cur;
|
||||
|
||||
if (!cur ||
|
||||
|
@ -238,26 +240,17 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
|
|||
|
||||
/* Disable the TX Watermark interrupt to stop TX */
|
||||
if (!dma)
|
||||
writel_relaxed(0, gi2c->se.base +
|
||||
SE_GENI_TX_WATERMARK_REG);
|
||||
goto irqret;
|
||||
}
|
||||
|
||||
if (dma) {
|
||||
writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
|
||||
} else if (dma) {
|
||||
dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
|
||||
dm_tx_st, dm_rx_st);
|
||||
goto irqret;
|
||||
}
|
||||
|
||||
if (cur->flags & I2C_M_RD &&
|
||||
m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
|
||||
} else if (cur->flags & I2C_M_RD &&
|
||||
m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
|
||||
u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
|
||||
|
||||
for (j = 0; j < rxcnt; j++) {
|
||||
u32 val;
|
||||
int p = 0;
|
||||
|
||||
val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn);
|
||||
p = 0;
|
||||
val = readl_relaxed(base + SE_GENI_RX_FIFOn);
|
||||
while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
|
||||
cur->buf[gi2c->cur_rd++] = val & 0xff;
|
||||
val >>= 8;
|
||||
|
@ -270,44 +263,39 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
|
|||
m_stat & M_TX_FIFO_WATERMARK_EN) {
|
||||
for (j = 0; j < gi2c->tx_wm; j++) {
|
||||
u32 temp;
|
||||
u32 val = 0;
|
||||
int p = 0;
|
||||
|
||||
val = 0;
|
||||
p = 0;
|
||||
while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
|
||||
temp = cur->buf[gi2c->cur_wr++];
|
||||
val |= temp << (p * 8);
|
||||
p++;
|
||||
}
|
||||
writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn);
|
||||
writel_relaxed(val, base + SE_GENI_TX_FIFOn);
|
||||
/* TX Complete, Disable the TX Watermark interrupt */
|
||||
if (gi2c->cur_wr == cur->len) {
|
||||
writel_relaxed(0, gi2c->se.base +
|
||||
SE_GENI_TX_WATERMARK_REG);
|
||||
writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
irqret:
|
||||
if (m_stat)
|
||||
writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR);
|
||||
|
||||
if (dma) {
|
||||
if (dm_tx_st)
|
||||
writel_relaxed(dm_tx_st, gi2c->se.base +
|
||||
SE_DMA_TX_IRQ_CLR);
|
||||
if (dm_rx_st)
|
||||
writel_relaxed(dm_rx_st, gi2c->se.base +
|
||||
SE_DMA_RX_IRQ_CLR);
|
||||
}
|
||||
if (m_stat)
|
||||
writel_relaxed(m_stat, base + SE_GENI_M_IRQ_CLEAR);
|
||||
|
||||
if (dma && dm_tx_st)
|
||||
writel_relaxed(dm_tx_st, base + SE_DMA_TX_IRQ_CLR);
|
||||
if (dma && dm_rx_st)
|
||||
writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
|
||||
|
||||
/* if this is err with done-bit not set, handle that through timeout. */
|
||||
if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN)
|
||||
complete(&gi2c->done);
|
||||
else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE)
|
||||
complete(&gi2c->done);
|
||||
else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
|
||||
if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
|
||||
dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
|
||||
dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
|
||||
complete(&gi2c->done);
|
||||
|
||||
spin_unlock_irqrestore(&gi2c->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -365,29 +353,24 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
u32 m_param)
|
||||
{
|
||||
dma_addr_t rx_dma;
|
||||
enum geni_se_xfer_mode mode;
|
||||
unsigned long time_left = XFER_TIMEOUT;
|
||||
unsigned long time_left;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
gi2c->cur = msg;
|
||||
mode = GENI_SE_FIFO;
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
mode = GENI_SE_DMA;
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
geni_se_select_mode(&gi2c->se, mode);
|
||||
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param);
|
||||
if (mode == GENI_SE_DMA) {
|
||||
int ret;
|
||||
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_READ, m_param);
|
||||
|
||||
ret = geni_se_rx_dma_prep(&gi2c->se, dma_buf, msg->len,
|
||||
&rx_dma);
|
||||
if (ret) {
|
||||
mode = GENI_SE_FIFO;
|
||||
geni_se_select_mode(&gi2c->se, mode);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
|
||||
}
|
||||
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
|
||||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
|
@ -395,12 +378,13 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
geni_i2c_abort_xfer(gi2c);
|
||||
|
||||
gi2c->cur_rd = 0;
|
||||
if (mode == GENI_SE_DMA) {
|
||||
if (dma_buf) {
|
||||
if (gi2c->err)
|
||||
geni_i2c_rx_fsm_rst(gi2c);
|
||||
geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len);
|
||||
geni_se_rx_dma_unprep(se, rx_dma, len);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
|
||||
}
|
||||
|
||||
return gi2c->err;
|
||||
}
|
||||
|
||||
|
@ -408,45 +392,41 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
u32 m_param)
|
||||
{
|
||||
dma_addr_t tx_dma;
|
||||
enum geni_se_xfer_mode mode;
|
||||
unsigned long time_left;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
gi2c->cur = msg;
|
||||
mode = GENI_SE_FIFO;
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
mode = GENI_SE_DMA;
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
geni_se_select_mode(&gi2c->se, mode);
|
||||
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param);
|
||||
if (mode == GENI_SE_DMA) {
|
||||
int ret;
|
||||
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
|
||||
|
||||
ret = geni_se_tx_dma_prep(&gi2c->se, dma_buf, msg->len,
|
||||
&tx_dma);
|
||||
if (ret) {
|
||||
mode = GENI_SE_FIFO;
|
||||
geni_se_select_mode(&gi2c->se, mode);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
|
||||
}
|
||||
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
|
||||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */
|
||||
writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG);
|
||||
if (!dma_buf) /* Get FIFO IRQ */
|
||||
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!time_left)
|
||||
geni_i2c_abort_xfer(gi2c);
|
||||
|
||||
gi2c->cur_wr = 0;
|
||||
if (mode == GENI_SE_DMA) {
|
||||
if (dma_buf) {
|
||||
if (gi2c->err)
|
||||
geni_i2c_tx_fsm_rst(gi2c);
|
||||
geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len);
|
||||
geni_se_tx_dma_unprep(se, tx_dma, len);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
|
||||
}
|
||||
|
||||
return gi2c->err;
|
||||
}
|
||||
|
||||
|
@ -474,6 +454,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
|
|||
|
||||
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
|
||||
|
||||
gi2c->cur = &msgs[i];
|
||||
if (msgs[i].flags & I2C_M_RD)
|
||||
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
|
||||
else
|
||||
|
|
|
@ -1088,11 +1088,6 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
|
|||
writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
|
||||
|
||||
for (idx = 0; idx < num; idx++) {
|
||||
if (msgs[idx].len == 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qup_i2c_poll_state_i2c_master(qup)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
|
@ -1520,9 +1515,6 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup,
|
|||
|
||||
/* All i2c_msgs should be transferred using either dma or cpu */
|
||||
for (idx = 0; idx < num; idx++) {
|
||||
if (msgs[idx].len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (msgs[idx].flags & I2C_M_RD)
|
||||
max_rx_len = max_t(unsigned int, max_rx_len,
|
||||
msgs[idx].len);
|
||||
|
@ -1636,9 +1628,14 @@ static const struct i2c_algorithm qup_i2c_algo_v2 = {
|
|||
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
|
||||
*/
|
||||
static const struct i2c_adapter_quirks qup_i2c_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
.max_read_len = QUP_READ_LIMIT,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
};
|
||||
|
||||
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
|
||||
{
|
||||
clk_prepare_enable(qup->clk);
|
||||
|
@ -1701,6 +1698,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
|
|||
is_qup_v1 = true;
|
||||
} else {
|
||||
qup->adap.algo = &qup_i2c_algo_v2;
|
||||
qup->adap.quirks = &qup_i2c_quirks_v2;
|
||||
is_qup_v1 = false;
|
||||
if (acpi_match_device(qup_i2c_acpi_match, qup->dev))
|
||||
goto nodma;
|
||||
|
|
|
@ -947,27 +947,9 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_runtime_nop(struct device *dev)
|
||||
{
|
||||
/* Runtime PM callback shared between ->runtime_suspend()
|
||||
* and ->runtime_resume(). Simply returns success.
|
||||
*
|
||||
* This driver re-initializes all registers after
|
||||
* pm_runtime_get_sync() anyway so there is no need
|
||||
* to save and restore registers here.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
|
||||
.runtime_suspend = sh_mobile_i2c_runtime_nop,
|
||||
.runtime_resume = sh_mobile_i2c_runtime_nop,
|
||||
};
|
||||
|
||||
static struct platform_driver sh_mobile_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-sh_mobile",
|
||||
.pm = &sh_mobile_i2c_dev_pm_ops,
|
||||
.of_match_table = sh_mobile_i2c_dt_ids,
|
||||
},
|
||||
.probe = sh_mobile_i2c_probe,
|
||||
|
|
|
@ -404,7 +404,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
|
|||
if (i2c->state == STATE_READ)
|
||||
goto prepare_read;
|
||||
|
||||
/* fallthru */
|
||||
/* fall through */
|
||||
|
||||
case STATE_WRITE:
|
||||
if (bsr & SYNQUACER_I2C_BSR_LRB) {
|
||||
|
|
|
@ -684,9 +684,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
|
||||
tegra_i2c_flush_fifos(i2c_dev);
|
||||
|
||||
if (msg->len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
i2c_dev->msg_buf = msg->buf;
|
||||
i2c_dev->msg_buf_remaining = msg->len;
|
||||
i2c_dev->msg_err = I2C_ERR_NONE;
|
||||
|
@ -831,6 +828,7 @@ static const struct i2c_algorithm tegra_i2c_algo = {
|
|||
|
||||
/* payload size is only 12 bit */
|
||||
static const struct i2c_adapter_quirks tegra_i2c_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
.max_read_len = 4096,
|
||||
.max_write_len = 4096,
|
||||
};
|
||||
|
|
|
@ -98,6 +98,7 @@ struct uniphier_fi2c_priv {
|
|||
unsigned int flags;
|
||||
unsigned int busy_cnt;
|
||||
unsigned int clk_cycle;
|
||||
spinlock_t lock; /* IRQ synchronization */
|
||||
};
|
||||
|
||||
static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
|
||||
|
@ -142,9 +143,10 @@ static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
|
|||
writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
|
||||
}
|
||||
|
||||
static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv)
|
||||
static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
|
||||
u32 mask)
|
||||
{
|
||||
writel(-1, priv->membase + UNIPHIER_FI2C_IC);
|
||||
writel(mask, priv->membase + UNIPHIER_FI2C_IC);
|
||||
}
|
||||
|
||||
static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
|
||||
|
@ -162,12 +164,17 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
|
|||
struct uniphier_fi2c_priv *priv = dev_id;
|
||||
u32 irq_status;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
|
||||
irq_status &= priv->enabled_irqs;
|
||||
|
||||
dev_dbg(&priv->adap.dev,
|
||||
"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
|
||||
priv->enabled_irqs, irq_status);
|
||||
|
||||
uniphier_fi2c_clear_irqs(priv, irq_status);
|
||||
|
||||
if (irq_status & UNIPHIER_FI2C_INT_STOP)
|
||||
goto complete;
|
||||
|
||||
|
@ -230,6 +237,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
|
|||
goto handled;
|
||||
}
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return IRQ_NONE;
|
||||
|
||||
data_done:
|
||||
|
@ -244,7 +253,7 @@ complete:
|
|||
}
|
||||
|
||||
handled:
|
||||
uniphier_fi2c_clear_irqs(priv);
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -252,6 +261,8 @@ handled:
|
|||
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
|
||||
{
|
||||
priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
|
||||
/* do not use TX byte counter */
|
||||
writel(0, priv->membase + UNIPHIER_FI2C_TBC);
|
||||
/* set slave address */
|
||||
|
@ -284,6 +295,8 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
|
|||
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
|
||||
}
|
||||
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
|
||||
/* set slave address with RD bit */
|
||||
writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
|
||||
priv->membase + UNIPHIER_FI2C_DTTX);
|
||||
|
@ -307,14 +320,16 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
|
|||
}
|
||||
|
||||
static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msg, bool stop)
|
||||
struct i2c_msg *msg, bool repeat,
|
||||
bool stop)
|
||||
{
|
||||
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
|
||||
bool is_read = msg->flags & I2C_M_RD;
|
||||
unsigned long time_left;
|
||||
unsigned long time_left, flags;
|
||||
|
||||
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
|
||||
is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
|
||||
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n",
|
||||
is_read ? "receive" : "transmit", msg->addr, msg->len,
|
||||
repeat, stop);
|
||||
|
||||
priv->len = msg->len;
|
||||
priv->buf = msg->buf;
|
||||
|
@ -326,22 +341,36 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
|||
priv->flags |= UNIPHIER_FI2C_STOP;
|
||||
|
||||
reinit_completion(&priv->comp);
|
||||
uniphier_fi2c_clear_irqs(priv);
|
||||
uniphier_fi2c_clear_irqs(priv, U32_MAX);
|
||||
writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
|
||||
priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
if (is_read)
|
||||
uniphier_fi2c_rx_init(priv, msg->addr);
|
||||
else
|
||||
uniphier_fi2c_tx_init(priv, msg->addr);
|
||||
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
|
||||
dev_dbg(&adap->dev, "start condition\n");
|
||||
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
|
||||
priv->membase + UNIPHIER_FI2C_CR);
|
||||
/*
|
||||
* For a repeated START condition, writing a slave address to the FIFO
|
||||
* kicks the controller. So, the UNIPHIER_FI2C_CR register should be
|
||||
* written only for a non-repeated START condition.
|
||||
*/
|
||||
if (!repeat)
|
||||
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
|
||||
priv->membase + UNIPHIER_FI2C_CR);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->enabled_irqs = 0;
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(&adap->dev, "transaction timeout.\n");
|
||||
uniphier_fi2c_recover(priv);
|
||||
|
@ -394,6 +423,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
|
|||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct i2c_msg *msg, *emsg = msgs + num;
|
||||
bool repeat = false;
|
||||
int ret;
|
||||
|
||||
ret = uniphier_fi2c_check_bus_busy(adap);
|
||||
|
@ -404,9 +434,11 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
|
|||
/* Emit STOP if it is the last message or I2C_M_STOP is set. */
|
||||
bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
|
||||
|
||||
ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
|
||||
ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
repeat = !stop;
|
||||
}
|
||||
|
||||
return num;
|
||||
|
@ -529,6 +561,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
|||
|
||||
priv->clk_cycle = clk_rate / bus_speed;
|
||||
init_completion(&priv->comp);
|
||||
spin_lock_init(&priv->lock);
|
||||
priv->adap.owner = THIS_MODULE;
|
||||
priv->adap.algo = &uniphier_fi2c_algo;
|
||||
priv->adap.dev.parent = dev;
|
||||
|
|
|
@ -281,9 +281,6 @@ static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c,
|
|||
int ret;
|
||||
int i;
|
||||
|
||||
if (msg->len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
zx2967_i2c_flush_fifos(i2c);
|
||||
|
||||
i2c->cur_trans = msg->buf;
|
||||
|
@ -498,6 +495,10 @@ static const struct i2c_algorithm zx2967_i2c_algo = {
|
|||
.functionality = zx2967_i2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks zx2967_i2c_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
};
|
||||
|
||||
static const struct of_device_id zx2967_i2c_of_match[] = {
|
||||
{ .compatible = "zte,zx296718-i2c", },
|
||||
{ },
|
||||
|
@ -568,6 +569,7 @@ static int zx2967_i2c_probe(struct platform_device *pdev)
|
|||
strlcpy(i2c->adap.name, "zx2967 i2c adapter",
|
||||
sizeof(i2c->adap.name));
|
||||
i2c->adap.algo = &zx2967_i2c_algo;
|
||||
i2c->adap.quirks = &zx2967_i2c_quirks;
|
||||
i2c->adap.nr = pdev->id;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
|
|
|
@ -1922,6 +1922,11 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!adap->algo->master_xfer) {
|
||||
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* REVISIT the fault reporting model here is weak:
|
||||
*
|
||||
* - When we get an error after receiving N bytes from a slave,
|
||||
|
@ -1938,35 +1943,19 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
* one (discarding status on the second message) or errno
|
||||
* (discarding status on the first one).
|
||||
*/
|
||||
|
||||
if (adap->algo->master_xfer) {
|
||||
#ifdef DEBUG
|
||||
for (ret = 0; ret < num; ret++) {
|
||||
dev_dbg(&adap->dev,
|
||||
"master_xfer[%d] %c, addr=0x%02x, len=%d%s\n",
|
||||
ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W',
|
||||
msgs[ret].addr, msgs[ret].len,
|
||||
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (in_atomic() || irqs_disabled()) {
|
||||
ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
if (!ret)
|
||||
/* I2C activity is ongoing. */
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
}
|
||||
|
||||
ret = __i2c_transfer(adap, msgs, num);
|
||||
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
|
||||
return ret;
|
||||
if (in_atomic() || irqs_disabled()) {
|
||||
ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
if (!ret)
|
||||
/* I2C activity is ongoing. */
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
}
|
||||
|
||||
ret = __i2c_transfer(adap, msgs, num);
|
||||
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(i2c_transfer);
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ static int i2c_mux_probe(struct platform_device *pdev)
|
|||
|
||||
ret = of_property_read_u32(child, "reg", &chan);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "no reg property for node '%s'\n",
|
||||
child->name);
|
||||
dev_err(dev, "no reg property for node '%pOFn'\n",
|
||||
child);
|
||||
goto err_children;
|
||||
}
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, ltc4306_of_match);
|
|||
|
||||
static int ltc4306_probe(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
const struct chip_desc *chip;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct ltc4306 *data;
|
||||
|
|
|
@ -132,7 +132,7 @@ static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
|
|||
static int mlxcpld_mux_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct i2c_mux_core *muxc;
|
||||
int num, force;
|
||||
|
|
|
@ -347,7 +347,7 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
|||
static int pca954x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
|
|
@ -106,23 +106,6 @@ static unsigned int at24_write_timeout = 25;
|
|||
module_param_named(write_timeout, at24_write_timeout, uint, 0);
|
||||
MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
|
||||
|
||||
/*
|
||||
* Both reads and writes fail if the previous write didn't complete yet. This
|
||||
* macro loops a few times waiting at least long enough for one entire page
|
||||
* write to work while making sure that at least one iteration is run before
|
||||
* checking the break condition.
|
||||
*
|
||||
* It takes two parameters: a variable in which the future timeout in jiffies
|
||||
* will be stored and a temporary variable holding the time of the last
|
||||
* iteration of processing the request. Both should be unsigned integers
|
||||
* holding at least 32 bits.
|
||||
*/
|
||||
#define at24_loop_until_timeout(tout, op_time) \
|
||||
for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \
|
||||
op_time = 0; \
|
||||
op_time ? time_before(op_time, tout) : true; \
|
||||
usleep_range(1000, 1500), op_time = jiffies)
|
||||
|
||||
struct at24_chip_data {
|
||||
/*
|
||||
* these fields mirror their equivalents in
|
||||
|
@ -308,13 +291,22 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
|
|||
/* adjust offset for mac and serial read ops */
|
||||
offset += at24->offset_adj;
|
||||
|
||||
at24_loop_until_timeout(timeout, read_time) {
|
||||
timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
|
||||
do {
|
||||
/*
|
||||
* The timestamp shall be taken before the actual operation
|
||||
* to avoid a premature timeout in case of high CPU load.
|
||||
*/
|
||||
read_time = jiffies;
|
||||
|
||||
ret = regmap_bulk_read(regmap, offset, buf, count);
|
||||
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
|
||||
count, offset, ret, jiffies);
|
||||
if (!ret)
|
||||
return count;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1500);
|
||||
} while (time_before(read_time, timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -358,14 +350,23 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
|
|||
regmap = at24_client->regmap;
|
||||
client = at24_client->client;
|
||||
count = at24_adjust_write_count(at24, offset, count);
|
||||
timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
|
||||
|
||||
do {
|
||||
/*
|
||||
* The timestamp shall be taken before the actual operation
|
||||
* to avoid a premature timeout in case of high CPU load.
|
||||
*/
|
||||
write_time = jiffies;
|
||||
|
||||
at24_loop_until_timeout(timeout, write_time) {
|
||||
ret = regmap_bulk_write(regmap, offset, buf, count);
|
||||
dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
|
||||
count, offset, ret, jiffies);
|
||||
if (!ret)
|
||||
return count;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1500);
|
||||
} while (time_before(write_time, timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue