summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-xiic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-xiic.c')
-rw-r--r--drivers/i2c/busses/i2c-xiic.c356
1 files changed, 270 insertions, 86 deletions
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 71391b590ada..6bc1575cea6c 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -30,6 +30,8 @@
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
+#include <linux/spinlock.h>
#define DRIVER_NAME "xiic-i2c"
#define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0)
@@ -74,6 +76,9 @@ enum i2c_scl_freq {
* @smbus_block_read: Flag to handle block read
* @input_clk: Input clock to I2C controller
* @i2c_clk: I2C SCL frequency
+ * @atomic: Mode of transfer
+ * @atomic_lock: Lock for atomic transfer mode
+ * @atomic_xfer_state: See STATE_
*/
struct xiic_i2c {
struct device *dev;
@@ -96,6 +101,9 @@ struct xiic_i2c {
bool smbus_block_read;
unsigned long input_clk;
unsigned int i2c_clk;
+ bool atomic;
+ spinlock_t atomic_lock; /* Lock for atomic transfer mode */
+ enum xilinx_i2c_state atomic_xfer_state;
};
struct xiic_version_data {
@@ -224,6 +232,8 @@ static const struct timing_regs timing_reg_values[] = {
#define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000))
/* timeout waiting for the controller finish transfers */
#define XIIC_XFER_TIMEOUT (msecs_to_jiffies(10000))
+/* timeout waiting for the controller finish transfers in micro seconds */
+#define XIIC_XFER_TIMEOUT_US 10000000
/*
* The following constant is used for the device global interrupt enable
@@ -238,6 +248,29 @@ static const struct timing_regs timing_reg_values[] = {
static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num);
static void __xiic_start_xfer(struct xiic_i2c *i2c);
+static int xiic_i2c_runtime_suspend(struct device *dev)
+{
+ struct xiic_i2c *i2c = dev_get_drvdata(dev);
+
+ clk_disable(i2c->clk);
+
+ return 0;
+}
+
+static int xiic_i2c_runtime_resume(struct device *dev)
+{
+ struct xiic_i2c *i2c = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(i2c->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable clock.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* For the register read and write functions, a little-endian and big-endian
* version are necessary. Endianness is detected during the probe function.
@@ -374,9 +407,10 @@ static int xiic_setclk(struct xiic_i2c *i2c)
unsigned int index = 0;
u32 reg_val;
- dev_dbg(i2c->adap.dev.parent,
- "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n",
- __func__, i2c->input_clk, i2c->i2c_clk);
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent,
+ "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n",
+ __func__, i2c->input_clk, i2c->i2c_clk);
/* If not specified in DT, do not configure in SW. Rely only on Vivado design */
if (!i2c->i2c_clk || !i2c->input_clk)
@@ -467,7 +501,8 @@ static int xiic_reinit(struct xiic_i2c *i2c)
return ret;
/* Enable interrupts */
- xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+ if (!i2c->atomic)
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
@@ -549,11 +584,12 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
- dev_dbg(i2c->adap.dev.parent,
- "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n",
- __func__, bytes_in_fifo, xiic_rx_space(i2c),
- xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent,
+ "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n",
+ __func__, bytes_in_fifo, xiic_rx_space(i2c),
+ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
if (bytes_in_fifo > xiic_rx_space(i2c))
bytes_in_fifo = xiic_rx_space(i2c);
@@ -612,6 +648,26 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
}
}
+static bool xiic_error_check(struct xiic_i2c *i2c)
+{
+ bool status = false;
+ u32 pend, isr, ier;
+
+ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+ pend = isr & ier;
+
+ if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
+ ((pend & XIIC_INTR_TX_ERROR_MASK) &&
+ !(pend & XIIC_INTR_RX_FULL_MASK))) {
+ xiic_reinit(i2c);
+ status = true;
+ if (i2c->tx_msg || i2c->rx_msg)
+ i2c->atomic_xfer_state = STATE_ERROR;
+ }
+ return status;
+}
+
static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
{
/* return the actual space left in the FIFO */
@@ -625,8 +681,9 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
len = (len > fifo_space) ? fifo_space : len;
- dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
- __func__, len, fifo_space);
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
+ __func__, len, fifo_space);
while (len--) {
u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
@@ -649,9 +706,13 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
~XIIC_CR_MSMS_MASK);
}
- dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
}
xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+
+ if (i2c->atomic && xiic_error_check(i2c))
+ return;
}
}
@@ -772,14 +833,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
goto out;
}
- xiic_fill_tx_fifo(i2c);
-
- /* current message sent and there is space in the fifo */
- if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
+ if (xiic_tx_space(i2c)) {
+ xiic_fill_tx_fifo(i2c);
+ } else {
+ /* current message fully written */
dev_dbg(i2c->adap.dev.parent,
"%s end of message sent, nmsgs: %d\n",
__func__, i2c->nmsgs);
- if (i2c->nmsgs > 1) {
+ /* Don't move onto the next message until the TX FIFO empties,
+ * to ensure that a NAK is not missed.
+ */
+ if (i2c->nmsgs > 1 && (pend & XIIC_INTR_TX_EMPTY_MASK)) {
i2c->nmsgs--;
i2c->tx_msg++;
xfer_more = 1;
@@ -790,11 +854,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
"%s Got TX IRQ but no more to do...\n",
__func__);
}
- } else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
- /* current frame is sent and is last,
- * make sure to disable tx half
- */
- xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+ }
}
if (pend & XIIC_INTR_BNB_MASK) {
@@ -844,45 +904,62 @@ static int xiic_bus_busy(struct xiic_i2c *i2c)
return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
}
-static int xiic_busy(struct xiic_i2c *i2c)
+static int xiic_wait_not_busy(struct xiic_i2c *i2c)
{
int tries = 3;
int err;
- if (i2c->tx_msg || i2c->rx_msg)
- return -EBUSY;
-
- /* In single master mode bus can only be busy, when in use by this
- * driver. If the register indicates bus being busy for some reason we
- * should ignore it, since bus will never be released and i2c will be
- * stuck forever.
- */
- if (i2c->singlemaster) {
- return 0;
- }
-
/* for instance if previous transfer was terminated due to TX error
* it might be that the bus is on it's way to become available
* give it at most 3 ms to wake
*/
err = xiic_bus_busy(i2c);
while (err && tries--) {
- msleep(1);
+ if (i2c->atomic)
+ udelay(1000);
+ else
+ usleep_range(1000, 1100);
err = xiic_bus_busy(i2c);
}
return err;
}
+static void xiic_recv_atomic(struct xiic_i2c *i2c)
+{
+ while (xiic_rx_space(i2c)) {
+ if (xiic_getreg32(i2c, XIIC_IISR_OFFSET) & XIIC_INTR_RX_FULL_MASK) {
+ xiic_read_rx(i2c);
+
+ /* Clear Rx full and Tx error interrupts. */
+ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
+ XIIC_INTR_TX_ERROR_MASK);
+ }
+ if (xiic_error_check(i2c))
+ return;
+ }
+
+ i2c->rx_msg = NULL;
+ xiic_irq_clr_en(i2c, XIIC_INTR_TX_ERROR_MASK);
+
+ /* send next message if this wasn't the last. */
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ __xiic_start_xfer(i2c);
+ }
+}
+
static void xiic_start_recv(struct xiic_i2c *i2c)
{
u16 rx_watermark;
u8 cr = 0, rfd_set = 0;
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
- dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
/* Disable Tx interrupts */
xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK | XIIC_INTR_TX_EMPTY_MASK);
@@ -980,9 +1057,10 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
XIIC_CR_MSMS_MASK)
& ~(XIIC_CR_DIR_IS_TX_MASK));
}
- dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n",
- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
}
if (i2c->nmsgs == 1)
@@ -992,10 +1070,55 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
/* the message is tx:ed */
i2c->tx_pos = msg->len;
+ i2c->prev_msg_tx = false;
+
/* Enable interrupts */
- xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+ if (!i2c->atomic)
+ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+ else
+ xiic_recv_atomic(i2c);
+}
- i2c->prev_msg_tx = false;
+static void xiic_send_rem_atomic(struct xiic_i2c *i2c)
+{
+ while (xiic_tx_space(i2c)) {
+ if (xiic_tx_fifo_space(i2c)) {
+ u16 data;
+
+ data = i2c->tx_msg->buf[i2c->tx_pos];
+ i2c->tx_pos++;
+ if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) {
+ /* last message in transfer -> STOP */
+ if (i2c->dynamic) {
+ data |= XIIC_TX_DYN_STOP_MASK;
+ } else {
+ u8 cr;
+ int status;
+
+ /* Wait till FIFO is empty so STOP is sent last */
+ status = xiic_wait_tx_empty(i2c);
+ if (status)
+ return;
+
+ /* Write to CR to stop */
+ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr &
+ ~XIIC_CR_MSMS_MASK);
+ }
+ }
+ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+ }
+ if (xiic_error_check(i2c))
+ return;
+ }
+
+ if (i2c->nmsgs > 1) {
+ i2c->nmsgs--;
+ i2c->tx_msg++;
+ __xiic_start_xfer(i2c);
+ } else {
+ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+ }
}
static void xiic_start_send(struct xiic_i2c *i2c)
@@ -1004,11 +1127,13 @@ static void xiic_start_send(struct xiic_i2c *i2c)
u16 data;
struct i2c_msg *msg = i2c->tx_msg;
- dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
- __func__, msg, msg->len);
- dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ if (!i2c->atomic) {
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
+ __func__, msg, msg->len);
+ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
+ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+ }
if (i2c->dynamic) {
/* write the address */
@@ -1073,19 +1198,27 @@ static void xiic_start_send(struct xiic_i2c *i2c)
XIIC_INTR_TX_ERROR_MASK |
XIIC_INTR_BNB_MASK);
}
+
i2c->prev_msg_tx = true;
+
+ if (i2c->atomic && !i2c->atomic_xfer_state)
+ xiic_send_rem_atomic(i2c);
}
static void __xiic_start_xfer(struct xiic_i2c *i2c)
{
int fifo_space = xiic_tx_fifo_space(i2c);
- dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
- __func__, i2c->tx_msg, fifo_space);
+ if (!i2c->atomic)
+ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
+ __func__, i2c->tx_msg, fifo_space);
if (!i2c->tx_msg)
return;
+ if (i2c->atomic && xiic_error_check(i2c))
+ return;
+
i2c->rx_pos = 0;
i2c->tx_pos = 0;
i2c->state = STATE_START;
@@ -1102,16 +1235,49 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
bool broken_read, max_read_len, smbus_blk_read;
int ret, count;
- mutex_lock(&i2c->lock);
+ if (i2c->atomic)
+ spin_lock(&i2c->atomic_lock);
+ else
+ mutex_lock(&i2c->lock);
- ret = xiic_busy(i2c);
- if (ret)
+ if (i2c->tx_msg || i2c->rx_msg) {
+ dev_err(i2c->adap.dev.parent,
+ "cannot start a transfer while busy\n");
+ ret = -EBUSY;
goto out;
+ }
+
+ i2c->atomic_xfer_state = STATE_DONE;
+
+ /* In single master mode bus can only be busy, when in use by this
+ * driver. If the register indicates bus being busy for some reason we
+ * should ignore it, since bus will never be released and i2c will be
+ * stuck forever.
+ */
+ if (!i2c->singlemaster) {
+ ret = xiic_wait_not_busy(i2c);
+ if (ret) {
+ /* If the bus is stuck in a busy state, such as due to spurious low
+ * pulses on the bus causing a false start condition to be detected,
+ * then try to recover by re-initializing the controller and check
+ * again if the bus is still busy.
+ */
+ dev_warn(i2c->adap.dev.parent, "I2C bus busy timeout, reinitializing\n");
+ ret = xiic_reinit(i2c);
+ if (ret)
+ goto out;
+ ret = xiic_wait_not_busy(i2c);
+ if (ret)
+ goto out;
+ }
+ }
i2c->tx_msg = msgs;
i2c->rx_msg = NULL;
i2c->nmsgs = num;
- init_completion(&i2c->completion);
+
+ if (!i2c->atomic)
+ init_completion(&i2c->completion);
/* Decide standard mode or Dynamic mode */
i2c->dynamic = true;
@@ -1146,7 +1312,10 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
__xiic_start_xfer(i2c);
out:
- mutex_unlock(&i2c->lock);
+ if (i2c->atomic)
+ spin_unlock(&i2c->atomic_lock);
+ else
+ mutex_unlock(&i2c->lock);
return ret;
}
@@ -1164,10 +1333,8 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
return err;
err = xiic_start_xfer(i2c, msgs, num);
- if (err < 0) {
- dev_err(adap->dev.parent, "Error xiic_start_xfer\n");
+ if (err < 0)
goto out;
- }
err = wait_for_completion_timeout(&i2c->completion, XIIC_XFER_TIMEOUT);
mutex_lock(&i2c->lock);
@@ -1187,6 +1354,44 @@ out:
return err;
}
+static int xiic_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct xiic_i2c *i2c = i2c_get_adapdata(adap);
+ u32 status_reg;
+ int err;
+
+ err = xiic_i2c_runtime_resume(i2c->dev);
+ if (err)
+ return err;
+
+ i2c->atomic = true;
+ err = xiic_start_xfer(i2c, msgs, num);
+ if (err < 0)
+ return err;
+
+ err = readl_poll_timeout_atomic(i2c->base + XIIC_SR_REG_OFFSET,
+ status_reg, !(status_reg & XIIC_SR_BUS_BUSY_MASK),
+ 1, XIIC_XFER_TIMEOUT_US);
+
+ if (err) /* Timeout */
+ err = -ETIMEDOUT;
+
+ spin_lock(&i2c->atomic_lock);
+ if (err || i2c->state) {
+ i2c->tx_msg = NULL;
+ i2c->rx_msg = NULL;
+ i2c->nmsgs = 0;
+ }
+
+ err = (i2c->atomic_xfer_state == STATE_DONE) ? num : -EIO;
+ spin_unlock(&i2c->atomic_lock);
+
+ i2c->atomic = false;
+ xiic_i2c_runtime_suspend(i2c->dev);
+
+ return err;
+}
+
static u32 xiic_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
@@ -1194,6 +1399,7 @@ static u32 xiic_func(struct i2c_adapter *adap)
static const struct i2c_algorithm xiic_algorithm = {
.master_xfer = xiic_xfer,
+ .master_xfer_atomic = xiic_xfer_atomic,
.functionality = xiic_func,
};
@@ -1257,6 +1463,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
DRIVER_NAME " %s", pdev->name);
mutex_init(&i2c->lock);
+ spin_lock_init(&i2c->atomic_lock);
i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(i2c->clk))
@@ -1282,7 +1489,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
pdev->name, i2c);
if (ret < 0) {
- dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n");
goto err_pm_disable;
}
@@ -1303,7 +1510,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
ret = xiic_reinit(i2c);
if (ret < 0) {
- dev_err(&pdev->dev, "Cannot xiic_reinit\n");
+ dev_err_probe(&pdev->dev, ret, "Cannot xiic_reinit\n");
goto err_pm_disable;
}
@@ -1326,8 +1533,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
return 0;
err_pm_disable:
- pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
return ret;
}
@@ -1354,29 +1561,6 @@ static void xiic_i2c_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(&pdev->dev);
}
-static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev)
-{
- struct xiic_i2c *i2c = dev_get_drvdata(dev);
-
- clk_disable(i2c->clk);
-
- return 0;
-}
-
-static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev)
-{
- struct xiic_i2c *i2c = dev_get_drvdata(dev);
- int ret;
-
- ret = clk_enable(i2c->clk);
- if (ret) {
- dev_err(dev, "Cannot enable clock.\n");
- return ret;
- }
-
- return 0;
-}
-
static const struct dev_pm_ops xiic_dev_pm_ops = {
SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend,
xiic_i2c_runtime_resume, NULL)
@@ -1384,7 +1568,7 @@ static const struct dev_pm_ops xiic_dev_pm_ops = {
static struct platform_driver xiic_i2c_driver = {
.probe = xiic_i2c_probe,
- .remove_new = xiic_i2c_remove,
+ .remove = xiic_i2c_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(xiic_of_match),