mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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
63b96983a5
("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>
This commit is contained in:
parent
29c9e85d4d
commit
445094c8a9
1 changed files with 44 additions and 2 deletions
|
@ -194,6 +194,11 @@ struct exynos5_i2c {
|
||||||
*/
|
*/
|
||||||
int trans_done;
|
int trans_done;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called from atomic context, don't use interrupts.
|
||||||
|
*/
|
||||||
|
unsigned int atomic;
|
||||||
|
|
||||||
/* Controller operating frequency */
|
/* Controller operating frequency */
|
||||||
unsigned int op_clock;
|
unsigned int op_clock;
|
||||||
|
|
||||||
|
@ -711,6 +716,22 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
|
||||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
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,
|
static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||||
struct i2c_msg *msgs, int stop)
|
struct i2c_msg *msgs, int stop)
|
||||||
{
|
{
|
||||||
|
@ -725,8 +746,13 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||||
|
|
||||||
exynos5_i2c_message_start(i2c, stop);
|
exynos5_i2c_message_start(i2c, stop);
|
||||||
|
|
||||||
|
if (!i2c->atomic)
|
||||||
timeout = wait_for_completion_timeout(&i2c->msg_complete,
|
timeout = wait_for_completion_timeout(&i2c->msg_complete,
|
||||||
EXYNOS5_I2C_TIMEOUT);
|
EXYNOS5_I2C_TIMEOUT);
|
||||||
|
else
|
||||||
|
timeout = exynos5_i2c_poll_irqs_timeout(i2c,
|
||||||
|
EXYNOS5_I2C_TIMEOUT);
|
||||||
|
|
||||||
if (timeout == 0)
|
if (timeout == 0)
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
else
|
else
|
||||||
|
@ -777,6 +803,21 @@ err_pclk:
|
||||||
return ret ?: num;
|
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)
|
static u32 exynos5_i2c_func(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||||
|
@ -784,6 +825,7 @@ static u32 exynos5_i2c_func(struct i2c_adapter *adap)
|
||||||
|
|
||||||
static const struct i2c_algorithm exynos5_i2c_algorithm = {
|
static const struct i2c_algorithm exynos5_i2c_algorithm = {
|
||||||
.master_xfer = exynos5_i2c_xfer,
|
.master_xfer = exynos5_i2c_xfer,
|
||||||
|
.master_xfer_atomic = exynos5_i2c_xfer_atomic,
|
||||||
.functionality = exynos5_i2c_func,
|
.functionality = exynos5_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue