Skip to content

Commit 445094c

Browse files
mszyprowwsakernel
authored andcommitted
i2c: exynos5: add support for atomic transfers
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 <[email protected]> Reviewed-by: Andi Shyti <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 29c9e85 commit 445094c

File tree

1 file changed

+44
-2
lines changed

1 file changed

+44
-2
lines changed

drivers/i2c/busses/i2c-exynos5.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ struct exynos5_i2c {
194194
*/
195195
int trans_done;
196196

197+
/*
198+
* Called from atomic context, don't use interrupts.
199+
*/
200+
unsigned int atomic;
201+
197202
/* Controller operating frequency */
198203
unsigned int op_clock;
199204

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

719+
static bool exynos5_i2c_poll_irqs_timeout(struct exynos5_i2c *i2c,
720+
unsigned long timeout)
721+
{
722+
unsigned long time_left = jiffies + timeout;
723+
724+
while (time_before(jiffies, time_left) &&
725+
!((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) ||
726+
(i2c->state < 0))) {
727+
while (readl(i2c->regs + HSI2C_INT_ENABLE) &
728+
readl(i2c->regs + HSI2C_INT_STATUS))
729+
exynos5_i2c_irq(i2c->irq, i2c);
730+
usleep_range(100, 200);
731+
}
732+
return time_before(jiffies, time_left);
733+
}
734+
714735
static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
715736
struct i2c_msg *msgs, int stop)
716737
{
@@ -725,8 +746,13 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
725746

726747
exynos5_i2c_message_start(i2c, stop);
727748

728-
timeout = wait_for_completion_timeout(&i2c->msg_complete,
729-
EXYNOS5_I2C_TIMEOUT);
749+
if (!i2c->atomic)
750+
timeout = wait_for_completion_timeout(&i2c->msg_complete,
751+
EXYNOS5_I2C_TIMEOUT);
752+
else
753+
timeout = exynos5_i2c_poll_irqs_timeout(i2c,
754+
EXYNOS5_I2C_TIMEOUT);
755+
730756
if (timeout == 0)
731757
ret = -ETIMEDOUT;
732758
else
@@ -777,13 +803,29 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
777803
return ret ?: num;
778804
}
779805

806+
static int exynos5_i2c_xfer_atomic(struct i2c_adapter *adap,
807+
struct i2c_msg *msgs, int num)
808+
{
809+
struct exynos5_i2c *i2c = adap->algo_data;
810+
int ret;
811+
812+
disable_irq(i2c->irq);
813+
i2c->atomic = true;
814+
ret = exynos5_i2c_xfer(adap, msgs, num);
815+
i2c->atomic = false;
816+
enable_irq(i2c->irq);
817+
818+
return ret;
819+
}
820+
780821
static u32 exynos5_i2c_func(struct i2c_adapter *adap)
781822
{
782823
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
783824
}
784825

785826
static const struct i2c_algorithm exynos5_i2c_algorithm = {
786827
.master_xfer = exynos5_i2c_xfer,
828+
.master_xfer_atomic = exynos5_i2c_xfer_atomic,
787829
.functionality = exynos5_i2c_func,
788830
};
789831

0 commit comments

Comments
 (0)