Skip to content

Commit

Permalink
i2c: exynos5: add support for atomic transfers
Browse files Browse the repository at this point in the history
Add support for atomic transfers using polling mode with interrupts
intentionally disabled. This removes the warning introduced by commit
63b9698 ("i2c: core: introduce callbacks for atomic transfers")
during system reboot and power-off.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
  • Loading branch information
Marek Szyprowski authored and Wolfram Sang committed Oct 21, 2023
1 parent 29c9e85 commit 445094c
Showing 1 changed file with 44 additions and 2 deletions.
46 changes: 44 additions & 2 deletions drivers/i2c/busses/i2c-exynos5.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ struct exynos5_i2c {
*/
int trans_done;

/*
* Called from atomic context, don't use interrupts.
*/
unsigned int atomic;

/* Controller operating frequency */
unsigned int op_clock;

Expand Down Expand Up @@ -711,6 +716,22 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
spin_unlock_irqrestore(&i2c->lock, flags);
}

static bool exynos5_i2c_poll_irqs_timeout(struct exynos5_i2c *i2c,
unsigned long timeout)
{
unsigned long time_left = jiffies + timeout;

while (time_before(jiffies, time_left) &&
!((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) ||
(i2c->state < 0))) {
while (readl(i2c->regs + HSI2C_INT_ENABLE) &
readl(i2c->regs + HSI2C_INT_STATUS))
exynos5_i2c_irq(i2c->irq, i2c);
usleep_range(100, 200);
}
return time_before(jiffies, time_left);
}

static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
struct i2c_msg *msgs, int stop)
{
Expand All @@ -725,8 +746,13 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,

exynos5_i2c_message_start(i2c, stop);

timeout = wait_for_completion_timeout(&i2c->msg_complete,
EXYNOS5_I2C_TIMEOUT);
if (!i2c->atomic)
timeout = wait_for_completion_timeout(&i2c->msg_complete,
EXYNOS5_I2C_TIMEOUT);
else
timeout = exynos5_i2c_poll_irqs_timeout(i2c,
EXYNOS5_I2C_TIMEOUT);

if (timeout == 0)
ret = -ETIMEDOUT;
else
Expand Down Expand Up @@ -777,13 +803,29 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
return ret ?: num;
}

static int exynos5_i2c_xfer_atomic(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct exynos5_i2c *i2c = adap->algo_data;
int ret;

disable_irq(i2c->irq);
i2c->atomic = true;
ret = exynos5_i2c_xfer(adap, msgs, num);
i2c->atomic = false;
enable_irq(i2c->irq);

return ret;
}

static u32 exynos5_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}

static const struct i2c_algorithm exynos5_i2c_algorithm = {
.master_xfer = exynos5_i2c_xfer,
.master_xfer_atomic = exynos5_i2c_xfer_atomic,
.functionality = exynos5_i2c_func,
};

Expand Down

0 comments on commit 445094c

Please sign in to comment.